<?xml version="1.0" encoding="UTF-8"?><rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>Laravel &#8211; エンジニア見習い</title>
	<atom:link href="https://otonan-syusyoku.work/archives/tag/laravel/feed" rel="self" type="application/rss+xml" />
	<link>https://otonan-syusyoku.work</link>
	<description>三流プログラマー</description>
	<lastBuildDate>Tue, 06 Jan 2026 07:22:32 +0000</lastBuildDate>
	<language>ja</language>
	<sy:updatePeriod>
	hourly	</sy:updatePeriod>
	<sy:updateFrequency>
	1	</sy:updateFrequency>
	<generator>https://wordpress.org/?v=6.9.4</generator>

<image>
	<url>https://otonan-syusyoku.work/wp-content/uploads/2023/10/cropped-名称未設定のデザイン-16-32x32.png</url>
	<title>Laravel &#8211; エンジニア見習い</title>
	<link>https://otonan-syusyoku.work</link>
	<width>32</width>
	<height>32</height>
</image> 
	<item>
		<title>Laravel+Inertia+ReactをECSで動かしたい！ NginxとPHP-FPMのコンテナ分離</title>
		<link>https://otonan-syusyoku.work/archives/2153</link>
					<comments>https://otonan-syusyoku.work/archives/2153#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Tue, 28 Oct 2025 05:24:52 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[インフラ]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[DevOps]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[LAMP]]></category>
		<category><![CDATA[Laravel]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[React]]></category>
		<category><![CDATA[ネットワーク]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=2153</guid>

					<description><![CDATA[Laravel + Inertia (React/Vue) の組み合わせは、SPA（シングルページアプリケーション）の体験とサーバーサイド（Laravel）の書きやすさを両立できる、非常に強力な構成です。 しかし、ローカ [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Laravel + Inertia (React/Vue) の組み合わせは、SPA（シングルページアプリケーション）の体験とサーバーサイド（Laravel）の書きやすさを両立できる、非常に強力な構成です。</p>
<p>しかし、ローカルのDocker Compose環境では問題なく動作しても、AWSのECS Fargateのような本番環境にデプロイしようとすると、いくつかの疑問に直面します。</p>
<ul>
<li>「NginxとPHP-FPMコンテナはどう連携させるのがベスト？」</li>
<li>「<code>fastcgi_pass</code> ってローカルと設定を変える必要ある？」</li>
<li>「InertiaでビルドしたReactのJS/CSSファイルは、結局どのコンテナに置くのが正解？」</li>
</ul>
<p>この記事では、<code>fastcgi_pass</code> の基本から、ECS Fargateでの最適なコンテナ構成、そしてInertia/Reactプロジェクト特有の「静的ファイルの配置場所」問題までを、順を追って解説します。</p>
<h2>fastcgi_pass とは？</h2>
<h3>NginxとPHP-FPMの「橋渡し」</h3>
<p>まず基本のおさらいです。Nginxは高性能なWebサーバーですが、それ自体はPHPコードを実行できません。<br />
一方、PHP-FPMはPHPコードを実行することに特化したプロセス（サーバー）です。</p>
<p>Nginxがクライアント（ブラウザ）から <code>.php</code> ファイルへのリクエストを受け取ったとき、そのリクエストをPHP-FPMに処理してもらう必要があります。</p>
<p>このとき、Nginxの設定ファイル（<code>nginx.conf</code>）で、<b>「どのPHP-FPMに処理を依頼するか」の宛先を指定する</b>のが <code>fastcgi_pass</code> ディレクティブです。</p>
<div _ngcontent-ng-c535465467="" class="code-block ng-tns-c535465467-470 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression,attention;BardVeMetadataKey:[[&quot;r_4fea32b244968dc8&quot;,&quot;c_103da6cb53c10bc2&quot;,null,&quot;rc_8751fdc7f6beda59&quot;,null,null,&quot;ja&quot;,null,1,null,null,1,0]]">
<div _ngcontent-ng-c535465467="" class="formatted-code-block-internal-container ng-tns-c535465467-470">
<div _ngcontent-ng-c535465467="" class="animated-opacity ng-tns-c535465467-470">
<pre _ngcontent-ng-c535465467="" class="ng-tns-c535465467-470"><code _ngcontent-ng-c535465467="" role="text" data-test-id="code-content" class="code-container formatted ng-tns-c535465467-470"><span class="hljs-attribute">location</span> <span class="hljs-regexp">~ \.php$</span> {
    <span class="hljs-comment"># ...</span>
    <span class="hljs-comment"># ↓ この一行が「橋渡し」の指定</span>
    <span class="hljs-attribute">fastcgi_pass</span> php-fpm-server:<span class="hljs-number">9000</span>; 
}
</code></pre>
</div>
</div>
</div>
<p>&nbsp;</p>
<h2>ローカル開発 (Docker Compose) での構成</h2>
<p>ローカル開発では、「1コンテナ1責務」の原則に従い、NginxとPHP-FPMを別々のコンテナとして <code>docker-compose.yml</code> で定義するのが一般的です。</p>
<div _ngcontent-ng-c535465467="" class="code-block ng-tns-c535465467-471 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression,attention;BardVeMetadataKey:[[&quot;r_4fea32b244968dc8&quot;,&quot;c_103da6cb53c10bc2&quot;,null,&quot;rc_8751fdc7f6beda59&quot;,null,null,&quot;ja&quot;,null,1,null,null,1,0]]">
<div _ngcontent-ng-c535465467="" class="formatted-code-block-internal-container ng-tns-c535465467-471">
<div _ngcontent-ng-c535465467="" class="animated-opacity ng-tns-c535465467-471">
<pre _ngcontent-ng-c535465467="" class="ng-tns-c535465467-471"><code _ngcontent-ng-c535465467="" role="text" data-test-id="code-content" class="code-container formatted ng-tns-c535465467-471"><span class="hljs-comment"># docker-compose.yml (抜粋)</span>
<span class="hljs-attr">version:</span> <span class="hljs-string">'3'</span>
<span class="hljs-attr">services:</span>
  <span class="hljs-comment"># Nginxコンテナ</span>
  <span class="hljs-attr">nginx:</span>
    <span class="hljs-attr">image:</span> <span class="hljs-string">nginx:alpine</span>
    <span class="hljs-attr">ports:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">"80:80"</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./nginx.conf:/etc/nginx/conf.d/default.conf</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./laravel-project:/var/www/html</span>

  <span class="hljs-comment"># PHP-FPMコンテナ</span>
  <span class="hljs-attr">php:</span>
    <span class="hljs-attr">build:</span> <span class="hljs-string">.</span> <span class="hljs-comment"># PHP-FPMとLaravelコードを含むDockerfile</span>
    <span class="hljs-attr">volumes:</span>
      <span class="hljs-bullet">-</span> <span class="hljs-string">./laravel-project:/var/www/html</span>
</code></pre>
</div>
</div>
</div>
<p>&nbsp;</p>
<p>この構成では、NginxコンテナとPHPコンテナは <b>別々のネットワーク空間</b> に存在します。Docker Composeが提供する内部ネットワークを介して、サービス名で通信します。</p>
<p>したがって、NginxコンテナからPHPコンテナへは、<code>php</code> というサービス名（ホスト名）を使ってアクセスします。</p>
<div _ngcontent-ng-c535465467="" class="code-block ng-tns-c535465467-472 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression,attention;BardVeMetadataKey:[[&quot;r_4fea32b244968dc8&quot;,&quot;c_103da6cb53c10bc2&quot;,null,&quot;rc_8751fdc7f6beda59&quot;,null,null,&quot;ja&quot;,null,1,null,null,1,0]]">
<div _ngcontent-ng-c535465467="" class="formatted-code-block-internal-container ng-tns-c535465467-472">
<div _ngcontent-ng-c535465467="" class="animated-opacity ng-tns-c535465467-472">
<pre _ngcontent-ng-c535465467="" class="ng-tns-c535465467-472"><code _ngcontent-ng-c535465467="" role="text" data-test-id="code-content" class="code-container formatted ng-tns-c535465467-472"><span class="hljs-comment"># nginx.conf (Docker Compose用)</span>
<span class="hljs-attribute">location</span> <span class="hljs-regexp">~ \.php$</span> {
    <span class="hljs-comment"># ...</span>
    <span class="hljs-comment"># 'php' サービス（コンテナ）の 9000番ポートに転送</span>
    <span class="hljs-attribute">fastcgi_pass</span> php:<span class="hljs-number">9000</span>;
}
</code></pre>
</div>
</div>
</div>
<p>&nbsp;</p>
<p>（※ このTCP/IP通信によるパフォーマンスやセキュリティの懸念は、コンテナ間通信がDockerの内部ネットワークに限定されていれば、実用上ほとんど問題になりません。）</p>
<h2>【1タスク2コンテナ】本番 (ECS Fargate) での構成：</h2>
<p>さて、本題のECS Fargateです。<br />
ECSでは、<code>docker-compose.yml</code> に相当するものとして「タスク定義 (Task Definition)」を使います。</p>
<p>ここで重要なキーポイントは、<strong>「1つのタスク定義の中で、NginxコンテナとPHP-FPMコンテナの2つを定義する」</strong>ことです。</p>
<p><strong>これら2つのコンテナは、1セットで「Webアプリケーションサーバー」</strong>として機能します。</p>
<h3>ECS Fargateでのfastcgi_passはどうなる？</h3>
<p>ECSの同一タスク内で実行されるコンテナは、<b>同じネットワーク空間（ネットワークモード <code>awsvpc</code>）を共有します</b>。</p>
<p>これは、Nginxコンテナから見ると、PHP-FPMコンテナが「他人」ではなく、「自分自身（localhost）」として見えることを意味します。</p>
<p>したがって、ECS Fargate用のNginxイメージに含める <code>nginx.conf</code> の設定は、以下のようになります。</p>
<div _ngcontent-ng-c535465467="" class="code-block ng-tns-c535465467-473 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression,attention;BardVeMetadataKey:[[&quot;r_4fea32b244968dc8&quot;,&quot;c_103da6cb53c10bc2&quot;,null,&quot;rc_8751fdc7f6beda59&quot;,null,null,&quot;ja&quot;,null,1,null,null,1,0]]">
<div _ngcontent-ng-c535465467="" class="formatted-code-block-internal-container ng-tns-c535465467-473">
<div _ngcontent-ng-c535465467="" class="animated-opacity ng-tns-c535465467-473">
<pre _ngcontent-ng-c535465467="" class="ng-tns-c535465467-473"><code _ngcontent-ng-c535465467="" role="text" data-test-id="code-content" class="code-container formatted ng-tns-c535465467-473"><span class="hljs-comment"># nginx.conf (ECS Fargate用)</span>
<span class="hljs-attribute">location</span> <span class="hljs-regexp">~ \.php$</span> {
    <span class="hljs-comment"># ...</span>
    <span class="hljs-comment"># サービス名ではなく、localhost (127.0.0.1) を指定する</span>
    <span class="hljs-attribute">fastcgi_pass</span> <span class="hljs-number">127.0.0.1:9000</span>;
}
</code></pre>
</div>
</div>
</div>
<p>&nbsp;</p>
<h3>タスク定義のイメージ</h3>
<p>タスク定義では、以下のように設定します。</p>
<ul>
<li><b>コンテナ-A: <code>php-fpm-container</code></b>
<ul>
<li>イメージ: （Laravelコードを含むPHP-FPMイメージ）</li>
<li>ポートマッピング: <b>なし</b> (外部に公開する必要はないため)</li>
</ul>
</li>
<li><b>コンテナ-B: <code>nginx-container</code></b>
<ul>
<li>イメージ: （設定済みのnginx.confと静的ファイルを含むNginxイメージ）</li>
<li>ポートマッピング: <b><code>80:80</code></b> (ALBからのトラフィックを受け取るため)</li>
</ul>
</li>
</ul>
<p>ALB（ロードバランサー）からのトラフィックはNginxコンテナが受け取り、必要に応じて <code>localhost:9000</code> を介してPHP-FPMコンテナに処理を渡します。</p>
<h2>Inertia/Reactのビルドファイルはどこに置く？</h2>
<p>ここで、Inertia/React構成特有の問題に直面します。</p>
<p>「InertiaはLaravel（PHP）がビューを配信する仕組みだから、<code>npm run build</code> で生成された <code>public/build</code> フォルダは、PHP-FPMコンテナにだけ置けば良いのでは？」</p>
<p>これはよくある誤解ですが、<b>パフォーマンスと責務分離の観点から、ビルドした静的ファイル（JS/CSS）はNginxコンテナに配置するのが正解</b>です。</p>
<p>この理由を理解するために、Inertiaのページが読み込まれる2段階のフローを見てみましょう。</p>
<h3>ステップ1: HTMLシェルのリクエスト (PHP-FPMが処理)</h3>
<ol start="1">
<li>ブラウザが <code>https://example.com/dashboard</code> にアクセスします。</li>
<li>ALB → Nginxコンテナがリクエストを受け取ります。</li>
<li>NginxはこれがPHPのリクエストだと判断し、<code>fastcgi_pass 127.0.0.1:9000</code> を使って<b>PHP-FPMコンテナ</b>に転送します。</li>
<li>PHP (Laravel) が起動し、Inertiaは <code>app.blade.php</code> をレンダリングしようとします。</li>
<li>このとき、PHPは <b><code>public/build/manifest.json</code></b> を読み取り、HTMLに含めるべきJS/CSSのファイル名を特定します。</li>
<li>PHPは以下のようなHTMLの「ガワ」を<b>生成</b>し、Nginx経由でブラウザに返します。
<p><response-element class="" ng-version="0.0.0-PLACEHOLDER"><code-block _nghost-ng-c535465467="" class="ng-tns-c535465467-474 ng-star-inserted"></p>
<div _ngcontent-ng-c535465467="" class="code-block ng-tns-c535465467-474 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression,attention;BardVeMetadataKey:[[&quot;r_4fea32b244968dc8&quot;,&quot;c_103da6cb53c10bc2&quot;,null,&quot;rc_8751fdc7f6beda59&quot;,null,null,&quot;ja&quot;,null,1,null,null,1,0]]">
<div _ngcontent-ng-c535465467="" class="formatted-code-block-internal-container ng-tns-c535465467-474">
<div _ngcontent-ng-c535465467="" class="animated-opacity ng-tns-c535465467-474">
<pre _ngcontent-ng-c535465467="" class="ng-tns-c535465467-474"><code _ngcontent-ng-c535465467="" role="text" data-test-id="code-content" class="code-container formatted ng-tns-c535465467-474"><span class="hljs-tag">&lt;<span class="hljs-name">html</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">head</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">script</span> <span class="hljs-attr">src</span>=<span class="hljs-string">"/build/assets/app.12345.js"</span> <span class="hljs-attr">defer</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">script</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">link</span> <span class="hljs-attr">rel</span>=<span class="hljs-string">"stylesheet"</span> <span class="hljs-attr">href</span>=<span class="hljs-string">"/build/assets/app.67890.css"</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">head</span>&gt;</span>
<span class="hljs-tag">&lt;<span class="hljs-name">body</span>&gt;</span>
    <span class="hljs-tag">&lt;<span class="hljs-name">div</span> <span class="hljs-attr">id</span>=<span class="hljs-string">"app"</span> <span class="hljs-attr">data-page</span>=<span class="hljs-string">"..."</span>&gt;</span><span class="hljs-tag">&lt;/<span class="hljs-name">div</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">body</span>&gt;</span>
<span class="hljs-tag">&lt;/<span class="hljs-name">html</span>&gt;</span>
</code></pre>
</div>
</div>
</div>
<p></code-block></response-element></li>
</ol>
<h3>ステップ2: 静的アセット(JS/CSS)のリクエスト (Nginxが処理)</h3>
<ol start="1">
<li>ブラウザは、ステップ1で受け取ったHTMLを解析します。</li>
<li>「<code>/build/assets/app.12345.js</code> と <code>/build/assets/app.67890.css</code> が必要だ」と判断し、ブラウザは<b>別途2回のリクエスト</b>をサーバーに送信します。</li>
<li><b>このリクエストは、もはやPHPとは全く関係ありません。</b></li>
<li>ALB → <b>Nginxコンテナ</b>がこの2つのリクエストを受け取ります。</li>
<li>Nginxは「自分の管理下（<code>public</code> フォルダ）にそのファイルがあるか？」を探します。</li>
<li><b>Nginxコンテナに <code>public/build/</code> 以下の実体ファイルが存在するため</b>、NginxはPHP-FPMを起動することなく、それらの静的ファイルを<b>超高速で</b>ブラウザに直接返します。</li>
</ol>
<p>もし、NginxコンテナにJS/CSSファイルがなければ、このリクエストもPHP-FPMに転送されてしまい、「JSファイルを取得するためだけにLaravelを起動する」という深刻なパフォーマンスボトルネックが発生します。</p>
<h3>CI/CDでのベストプラクティス</h3>
<p>上記2ステップから、CI/CDパイプラインでDockerイメージをビルドする際は、以下の構成が最適です。</p>
<ol start="1">
<li><code>npm run build</code> を実行し、<code>public/build</code> ディレクトリを生成します。</li>
<li><b>PHP-FPMイメージのビルド:</b>
<ul>
<li>Laravelのコード（<code>app/</code>, <code>routes/</code> など）をコピーします。</li>
<li>ステップ1のために <b><code>public/build/manifest.json</code></b> をコピーします。（リンク生成に必要）</li>
</ul>
</li>
<li><b>Nginxイメージのビルド:</b>
<ul>
<li><code>nginx.conf</code> をコピーします。</li>
<li>ステップ2のために <b><code>public</code> フォルダ全体</b>（<code>index.php</code> と、<code>public/build</code> 以下の <b>全てのJS/CSSファイル</b> を含む）をコピーします。（静的アセットの配信用）</li>
</ul>
</li>
</ol>
<h3><b>結論</b></h3>
<p><code>manifest.json</code> はPHP-FPMコンテナに、JS/CSSの実体ファイルはNginxコンテナに必要です。</p>
<p>両方のイメージに <code>public</code> フォルダ（または <code>public/build</code>）全体をコピーするのが、最もシンプルで確実な方法です。</p>
<h2>まとめ</h2>
<p>ECS Fargateで Laravel + Inertia + React 構成を動かすための要点をまとめます。</p>
<ol start="1">
<li><b>構成</b>: 「1タスク2コンテナ（Nginx + PHP-FPM）」構成を採用します。</li>
<li><b><code>fastcgi_pass</code></b>: NginxからPHP-FPMへの通信は、同一タスク内のため <code>fastcgi_pass 127.0.0.1:9000;</code> を指定します。</li>
<li><b>静的ファイル</b>: ビルドしたJS/CSSは、パフォーマンス最適化のためNginxコンテナに配置し、Nginxから直接配信させます。</li>
<li><b><code>manifest.json</code></b>: HTMLシェル生成のため、PHP-FPMコンテナにも <code>manifest.json</code> が必要です。</li>
</ol>
<p>この構成により、PHP-FPMは動的処理に専念し、Nginxは静的ファイルの高速配信に専念するという、「1コンテナ1責務」のメリットを最大限に活かした、スケーラブルな本番環境を構築できます。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/2153/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Nginxの「upstream sent too big header」エラーを解決する：LaravelとPHP-FPM環境での対処法</title>
		<link>https://otonan-syusyoku.work/archives/2128</link>
					<comments>https://otonan-syusyoku.work/archives/2128#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Mon, 23 Jun 2025 15:04:51 +0000</pubDate>
				<category><![CDATA[インフラ]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[LAMP]]></category>
		<category><![CDATA[Laravel]]></category>
		<category><![CDATA[nginx]]></category>
		<category><![CDATA[PHP]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=2128</guid>

					<description><![CDATA[環境 Ubuntu：24.04 PHP：8.2 Laravel：11.x 起こったこと NginxをWebサーバーとして、LaravelアプリケーションとPHP-FPMを連携させている環境で、ある日突然 upstream [&#8230;]]]></description>
										<content:encoded><![CDATA[<h2 data-sourcepos="7:1-7:154">環境</h2>
<p>Ubuntu：24.04<br />
PHP：8.2<br />
Laravel：11.x</p>
<h2 data-sourcepos="5:1-5:183">起こったこと</h2>
<p data-sourcepos="5:1-5:183">NginxをWebサーバーとして、LaravelアプリケーションとPHP-FPMを連携させている環境で、ある日突然 <code>upstream sent too big header while reading response header from upstream</code> というエラーがNginxのエラーログに表示され、Webサイトが正常に表示されなくなリマした…</p>
<p data-sourcepos="7:1-7:154">調べていくと、このエラーは、<span class="sc_marker blue"><strong>PHP-FPM（アップストリームサーバー）がNginxに返そうとしたHTTPレスポンスヘッダーのサイズが、Nginxが受け入れられる設定値の上限を超えてしまった場合に発生</strong></span>します。</p>
<p data-sourcepos="7:1-7:154">特にLaravelのような動的なアプリケーションでは、セッション情報やクッキーの肥大化が原因で発生しやすい問題とのことでやんす。</p>
<h2 data-sourcepos="9:1-9:15">エラーが起きる原因は？</h2>
<p data-sourcepos="11:1-11:182">NginxがWebサーバーとしてクライアントからのリクエストを受け取り、それをバックエンドのPHP-FPM（FastCGIプロセス）に渡して処理してもらいます。</p>
<p data-sourcepos="11:1-11:182">PHP-FPMが処理を終えてNginxに応答を返す際、そのHTTPレスポンスにはヘッダー情報が含まれます。このヘッダー情報がNginxが設定しているバッファのサイズを超えると、エラーが発生してしまいます。</p>
<p data-sourcepos="13:1-13:24">主な原因として、以下のようなものが挙げられます。</p>
<ul data-sourcepos="15:3-18:0">
<li data-sourcepos="15:3-15:177"><strong>セッションデータの肥大化:</strong> Laravelなどのフレームワークでセッションをクッキーベースで管理している場合、ユーザーが多くの情報をセッションに保存したり、ショッピングカートに大量のアイテムを追加したりすると、クッキーのサイズが大きくなります。この大きなクッキー情報がレスポンスヘッダーに含まれることで、上限を超えてしまうことがあります。</li>
<li data-sourcepos="16:3-16:100"><strong>多数のクッキーやカスタムヘッダー:</strong> アプリケーションが非常に多くのクッキーを設定している、または独自のカスタムヘッダーを大量に追加している場合も、ヘッダー全体のサイズが大きくなります。</li>
<li data-sourcepos="17:3-18:0"><strong>リダイレクトループ:</strong> 不適切なリダイレクト設定により、ブラウザが何度もリダイレクトを繰り返す際、そのたびに新しいクッキーやヘッダーが付与され、最終的にヘッダーが大きくなってしまうケースも考えられます。</li>
</ul>
<h2 data-sourcepos="19:1-19:21">解決策：Nginxの設定を調整する</h2>
<p data-sourcepos="21:1-21:48">最も手軽で直接的な解決策は、Nginxが受け入れられるヘッダーバッファのサイズを増やすことです。</p>
<p data-sourcepos="23:1-23:162">Nginxの設定ファイル（通常は <code>/etc/nginx/nginx.conf</code> か、サイト固有の <code>.conf</code> ファイル）を開き、<code>http</code> ブロック内、または対象の <code>server</code> ブロック内に以下のディレクティブを追加または調整します。<code>http</code> ブロックに記述すると、すべてのバーチャルホストに適用されます。</p>
<div _ngcontent-ng-c1213168243="" class="code-block ng-tns-c1213168243-479 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression;BardVeMetadataKey:[[&quot;r_7b21b8e99d7c089f&quot;,&quot;c_6fface8cac75276a&quot;,null,&quot;rc_b9532f80be7d9863&quot;,null,null,&quot;ja&quot;,null,1,null,null,1,0]]">
<div _ngcontent-ng-c1213168243="" class="formatted-code-block-internal-container ng-tns-c1213168243-479">
<div _ngcontent-ng-c1213168243="" class="animated-opacity ng-tns-c1213168243-479">
<pre _ngcontent-ng-c1213168243="" class="ng-tns-c1213168243-479"><code _ngcontent-ng-c1213168243="" role="text" data-test-id="code-content" class="code-container formatted ng-tns-c1213168243-479" data-sourcepos="25:1-42:1"><span class="hljs-section">http</span> {
    <span class="hljs-comment"># ... 他の http ブロック内の設定 ...</span>

    <span class="hljs-comment"># upstream sent too big header エラー対策</span>
    <span class="hljs-comment"># PHP-FPM（FastCGI）からのレスポンスヘッダーに対応するため、fastcgi_ のディレクティブを設定します。</span>
    <span class="hljs-comment"># 必要に応じて proxy_ のディレクティブも設定しますが、PHP-FPMの場合はfastcgi_を優先します。</span>
    <span class="hljs-attribute">fastcgi_buffer_size</span> <span class="hljs-number">128k</span>;   <span class="hljs-comment"># FastCGIヘッダーバッファの初期サイズ。デフォルトは4k/8k。</span>
    <span class="hljs-attribute">fastcgi_buffers</span>     <span class="hljs-number">4</span> <span class="hljs-number">256k</span>; <span class="hljs-comment"># 256KBのバッファを4つ用意。合計1MB。</span>

    <span class="hljs-comment"># 必要に応じて、もしプロキシとして使用している場合も考慮するなら、こちらも設定</span>
    <span class="hljs-comment"># proxy_buffer_size   128k;</span>
    <span class="hljs-comment"># proxy_buffers       4 256k;</span>
    <span class="hljs-comment"># proxy_busy_buffers_size 256k;</span>

    <span class="hljs-comment"># ... 他の http ブロック内の設定 ...</span>
}
</code></pre>
</div>
</div>
</div>
<p>&nbsp;</p>
<h3 data-sourcepos="44:1-44:15"><strong>ディレクティブの解説</strong></h3>
<ul data-sourcepos="46:3-48:0">
<li data-sourcepos="46:3-46:150"><code>fastcgi_buffer_size</code>: NginxがFastCGIからのレスポンスヘッダーを読み込むための最初のバッファサイズを指定します。デフォルト値（通常は <code>4k</code> または <code>8k</code>）よりも大きな値（例：<code>128k</code>）を設定することで、大きなヘッダーにも対応できるようになります。</li>
<li data-sourcepos="47:3-48:0"><code>fastcgi_buffers</code>: ヘッダーを含むレスポンス全体をバッファリングするためのバッファの数とサイズを設定します。上記の例では、<code>256KB</code>のバッファを<code>4</code>つ使用し、合計で<code>1MB</code>のバッファスペースを確保します。</li>
</ul>
<p data-sourcepos="49:1-50:107"><strong>注意点:</strong> これらの値を必要以上に大きくしすぎると、Nginxが使用するメモリ量が増加し、サーバーリソースを圧迫する可能性があります。まずはエラーが出なくなる最小限の増加から試し、サーバーの負荷状況を見ながら調整してください。</p>
<h3 data-sourcepos="52:1-52:12">設定変更後の手順</h3>
<ol data-sourcepos="54:1-65:0">
<li data-sourcepos="54:1-54:46"><strong>Nginx設定ファイルを保存:</strong> 変更したNginx設定ファイルを保存します。</li>
<li data-sourcepos="55:1-59:60"><strong>設定ファイルのテスト:</strong> <response-element class="" ng-version="0.0.0-PLACEHOLDER"><code-block _nghost-ng-c1213168243="" class="ng-tns-c1213168243-480 ng-star-inserted">
<div _ngcontent-ng-c1213168243="" class="code-block ng-tns-c1213168243-480 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression;BardVeMetadataKey:[[&quot;r_7b21b8e99d7c089f&quot;,&quot;c_6fface8cac75276a&quot;,null,&quot;rc_b9532f80be7d9863&quot;,null,null,&quot;ja&quot;,null,1,null,null,1,0]]">
<div _ngcontent-ng-c1213168243="" class="code-block-decoration header-formatted gds-title-s ng-tns-c1213168243-480 ng-star-inserted"></div>
<div _ngcontent-ng-c1213168243="" class="formatted-code-block-internal-container ng-tns-c1213168243-480">
<div _ngcontent-ng-c1213168243="" class="animated-opacity ng-tns-c1213168243-480">
<pre _ngcontent-ng-c1213168243="" class="ng-tns-c1213168243-480"><code _ngcontent-ng-c1213168243="" role="text" data-test-id="code-content" class="code-container formatted ng-tns-c1213168243-480" data-sourcepos="56:5-58:17">sudo nginx -t</code></pre>
</div>
</div>
</div>
<p>&nbsp;</p>
<p></code-block></response-element>このコマンドで構文エラーがないかを確認します。<code>test is successful</code> と表示されればOKです。</li>
<li data-sourcepos="60:1-65:0"><strong>Nginxのリロード:</strong> <response-element class="" ng-version="0.0.0-PLACEHOLDER"><code-block _nghost-ng-c1213168243="" class="ng-tns-c1213168243-481 ng-star-inserted">
<div _ngcontent-ng-c1213168243="" class="code-block ng-tns-c1213168243-481 ng-animate-disabled ng-trigger ng-trigger-codeBlockRevealAnimation" jslog="223238;track:impression;BardVeMetadataKey:[[&quot;r_7b21b8e99d7c089f&quot;,&quot;c_6fface8cac75276a&quot;,null,&quot;rc_b9532f80be7d9863&quot;,null,null,&quot;ja&quot;,null,1,null,null,1,0]]">
<div _ngcontent-ng-c1213168243="" class="formatted-code-block-internal-container ng-tns-c1213168243-481">
<div _ngcontent-ng-c1213168243="" class="animated-opacity ng-tns-c1213168243-481">
<pre _ngcontent-ng-c1213168243="" class="ng-tns-c1213168243-481"><code _ngcontent-ng-c1213168243="" role="text" data-test-id="code-content" class="code-container formatted ng-tns-c1213168243-481" data-sourcepos="61:5-63:31">sudo systemctl reload nginx
</code></pre>
</div>
</div>
</div>
<p>&nbsp;</p>
<p></code-block></response-element> Nginxサービスをリロードして、新しい設定を適用します。</li>
</ol>
<p data-sourcepos="66:1-66:87">これで、Nginxが大きなHTTPレスポンスヘッダーを適切に処理できるようになり、「<code>upstream sent too big header</code>」エラーは解消されるはずです。</p>
<h2>根本的な解決策：Laravelアプリケーション側の最適化</h2>
<p data-sourcepos="70:1-70:87">Nginxの設定でエラーを抑制できますが、<strong>Laravelアプリケーション側で不必要に大きなヘッダーが生成されている</strong>場合は、そちらの最適化も検討することをお勧めします。</p>
<ul data-sourcepos="72:3-78:0">
<li data-sourcepos="72:3-73:202"><strong>セッションデータの見直し:</strong>
<ul data-sourcepos="73:7-73:202">
<li data-sourcepos="73:7-73:202">クッキーに保存しているセッションデータが大きすぎる場合、データベースやRedisなどの<strong>サーバーサイドストレージにセッションを保存する</strong>ようにLaravelの設定を変更することを検討してください。これにより、クッキーにセッションIDのみが保存されるため、クッキーのサイズを大幅に削減できます。Laravelのセッション設定は <code>config/session.php</code> で変更可能です。</li>
</ul>
</li>
<li data-sourcepos="74:3-75:73"><strong>クッキーの管理:</strong>
<ul data-sourcepos="75:7-75:73">
<li data-sourcepos="75:7-75:73">アプリケーションが設定しているクッキーの数や、個々のクッキーのサイズを減らせないかレビューします。不要なクッキーは削除しましょう。</li>
</ul>
</li>
<li data-sourcepos="76:3-78:0"><strong>カスタムヘッダーの確認:</strong>
<ul data-sourcepos="77:7-78:0">
<li data-sourcepos="77:7-78:0">アプリケーションがレスポンスに含めているカスタムHTTPヘッダーが多すぎないか、または内容が大きすぎないかを確認します。</li>
</ul>
</li>
</ul>
<p data-sourcepos="79:1-79:84">Nginxの設定調整で当面のエラーは解消されますが、アプリケーションの効率性を高めるためにも、Laravel側のヘッダー生成ロジックを見直すことは良いプラクティスです。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/2128/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【AWS】S3への通信量削減の手法</title>
		<link>https://otonan-syusyoku.work/archives/1842</link>
					<comments>https://otonan-syusyoku.work/archives/1842#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Sun, 15 Sep 2024 07:31:51 +0000</pubDate>
				<category><![CDATA[インフラ]]></category>
		<category><![CDATA[生涯独学]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[CakePHP]]></category>
		<category><![CDATA[LAMP]]></category>
		<category><![CDATA[Laravel]]></category>
		<category><![CDATA[サーバー]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=1842</guid>

					<description><![CDATA[便利なストレージサービスであるS3を皆さん使っていますか…!? 静的コンテツの配信サーバーの役割をこなしたり、イレブンナインの耐久性を持ったストレージサービスといった点からAWSの中でも大好きなサービスです。 便利が故に [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>便利なストレージサービスであるS3を皆さん使っていますか…!?</p>
<p>静的コンテツの配信サーバーの役割をこなしたり、イレブンナインの耐久性を持ったストレージサービスといった点からAWSの中でも大好きなサービスです。</p>
<p>便利が故にコスト面でネックになってしまう状況が多々あるかと思いましたので、個人的に経験したコストダウンの設計手法をご紹介したいと思いますー！</p>
<div class="sc_frame_wrap inline orange">
<div class="sc_frame_title">話すこと</div>
<div class="sc_frame">
<p>今回は設計について話します。<br />
実装については話しません。</p>
</div>
</div>
<h2>手始めに</h2>
<p>まず初めにS3に関わる費用のざっくりとした内訳を確認しておきましょう。</p>
<ul>
<li>ストレージ</li>
<li>データ転送（IN/OUT）</li>
<li>セキュリティコントロール</li>
<li>レプリケーション</li>
<li>etc&#8230;</li>
</ul>
<p>一般的な運用を想定すると <strong>ストレージ </strong>と <strong>データ転送 </strong>が費用の大部分を占めるはずです。</p>
<p>その中でストレージに関しては、<br />
不必要なデータを置かない, データのライフサイクルを短くする, ストレージクラスを最適なものに設定するなどはありますが、<span class="sc_marker blue"><strong>S3にどのようなデータを置くかは各システムで要件が異なってくるため、費用の削減はあまり期待できません。</strong></span></p>
<p>そうなってくるとデータ転送の部分でコストを最適化するのが必要になってきます。</p>
<h2>通信量削減の取り組み</h2>
<h3>イメージ図</h3>
<table style="border-collapse: collapse; width: 100%;">
<tbody>
<tr>
<td style="width: 50%;"><a href="https://otonan-syusyoku.work/archives/1842/flow-drawio" rel="attachment wp-att-1883"><img fetchpriority="high" decoding="async" src="https://otonan-syusyoku.work/wp-content/uploads/2024/09/flow.drawio.png" alt="" width="722" height="514" class="aligncenter size-full wp-image-1883" srcset="https://otonan-syusyoku.work/wp-content/uploads/2024/09/flow.drawio.png 722w, https://otonan-syusyoku.work/wp-content/uploads/2024/09/flow.drawio-300x214.png 300w" sizes="(max-width: 722px) 100vw, 722px" /></a></td>
<td style="width: 50%;"><a href="https://otonan-syusyoku.work/archives/1842/aws-s3-request-cosst" rel="attachment wp-att-1880"><img decoding="async" src="https://otonan-syusyoku.work/wp-content/uploads/2024/09/aws-s3-request-cosst.png" alt="" width="632" height="308" class="aligncenter size-full wp-image-1880" srcset="https://otonan-syusyoku.work/wp-content/uploads/2024/09/aws-s3-request-cosst.png 632w, https://otonan-syusyoku.work/wp-content/uploads/2024/09/aws-s3-request-cosst-300x146.png 300w" sizes="(max-width: 632px) 100vw, 632px" /></a></td>
</tr>
</tbody>
</table>
<h3>やりたいこと</h3>
<p><span class="sc_marker blue"><strong>S3に゙保管しているコンテンツを毎回S3からダウンロードすることを辞めるための設計</strong></span>です。</p>
<p>これにより、キャッシュを用いてS3からの転送量を大幅に減らすことができます。（サイトへのアクセスが多ければ多いほど今回の設計は意味を増してくると思います。</p>
<p>&nbsp;</p>
<p>添付した画像のフローを改めて文字に起こします。</p>
<ol>
<li><strong>ページアクセス</strong>後に、必要なViewやCSS、画像などがリクエストされます。</li>
<li>まずアプリケーションサーバー（EC2）にコンテンツがキャッシュされているか確認します。</li>
<li>キャッシュに存在する場合は、そのままレスポンスを返します（転送料金が発生しません）。</li>
<li>キャッシュに存在しない場合は、S3からコンテンツを取得し、その後キャッシュします（S3へのアクセスを減らす）。</li>
</ol>
<h3>ChatGPT に計算してもらった</h3>
<pre class="line-numbers"><code class="language-php">### 東京リージョン（Asia Pacific (Tokyo)）でのS3のデータ転送料金

2023年9月現在、東京リージョンでのS3のデータ転送料金は次の通りです：

- 最初の1GB: **無料**
- 1GB～10TBまでのデータ転送: **$0.114/GB**

これに基づいて、東京リージョンでの転送料金削減を計算します。

### 仮定
- 1回のアクセスでS3からダウンロードされるデータの量：**1MB**
- 1日のアクセス数：**10,000回**
- キャッシュ成功率：**80%**
- 東京リージョンでのS3データ転送料金：**$0.114/GB**

### 計算式（東京リージョン）
1MBのデータが10,000回ダウンロードされる場合：
```
1MB × 10,000 = 10,000MB = 10GB
```

#### S3へのアクセスがない場合のコスト（全アクセスがS3の場合）
```
10GB × 0.114 = $1.14
```

#### キャッシュ導入後のコスト
キャッシュ成功率80%の場合、S3へのアクセスが20%：
```
10,000 × 0.2 = 2,000回
```

2,000回分のダウンロードデータ量：
```
1MB × 2,000 = 2,000MB = 2GB
```

これに対する転送料金：
```
2GB × 0.114 = $0.228
```

#### 削減額
S3にすべてのリクエストを送る場合のコストは**$1.14**、キャッシュを利用した場合のコストは**$0.228**。
したがって、削減できる金額は：
```
$1.14 - $0.228 = $0.912
```

### 結論
キャッシュを使うことで、東京リージョンの場合は、
1日あたり約**$0.912**の転送料金削減が見込めます。

これを1ヶ月（30日）分に換算すると、約**$27.36**の削減が期待できます。

もちろん、アクセス数やキャッシュ成功率、ダウンロードデータのサイズによって結果は変わりますが、
このざっくりとした計算での削減効果は**80%**程度です。
</code></pre>
<h3>注意点①</h3>
<p><span class="sc_marker blue"><strong>キャッシュクリアの方法を適切に設定しない場合、全てのコンテンツリクエストがキャッシュデータを返却してしまいます。</strong></span></p>
<p>各方面から以下のようなお叱りが届いてしまうので、今回ご紹介した設計を取る場合は、しっかりとキャッシュクリアの戦略を練りましょう。。。</p>
<div class="voice left">
<div class="icon">
<p><img decoding="async" src="https://otonan-syusyoku.work/wp-content/uploads/2020/10/名称未設定のデザイン-69.png" /></p>
<div class="name">エンドユーザー</div>
</div>
<div class="text sc-inner-content sc_balloon left blue">
<p>ユーザーから保存したデータが古いままなんだけどどうなってるの!?</p>
</div>
</div>
<div class="sc_frame_wrap inline orange">
<div class="sc_frame_title">キャッシュクリア</div>
<div class="sc_frame">
<p>&#8211; バッチ処理にて定期的に削除する（1日1回、6時間毎に&#8230;<br />
&#8211; データの書き換えのタイミングで該当のキャッシュを削除</p>
</div>
</div>
<h3>注意点②</h3>
<p><span class="sc_marker blue"><strong>アプリケーションサーバーにコンテンツを配置するので、アプリケーションサーバー自体のストレージを圧迫する可能性が大いにあります。</strong></span><br />
アプリケーションサーバーのストレージを外部に移す目的でS3を導入している場合は、今回の手法は取れないので、CDNサービス等を用いてキャッシュさせるのも一つの手になってくると思います。</p>
<h3>注意点③</h3>
<p>注意点②と同様にアプリケーションサーバーにコンテンツを配置するが故の問題として、センシティブなデータをアプリケーションサーバーに配置する可能性があります。<br />
例： 個人情報の類のコンテンツ（運転免許証、何らかの明細）</p>
<p>これらを一時的にではありますが、アプリケーションサーバーに配置するのがシステム要件的にNGの場合は、絶対に今回の手法は取れません！</p>
<h2>最後に</h2>
<p>ちょいとした工夫でコストダウンを見込めますので、皆さんも試してみて欲しいですー！</p>
<p>システムの要件等で導入できなければごめんさい！！</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/1842/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【Laravel】MinIO にputできない問題が情けなさ過ぎた</title>
		<link>https://otonan-syusyoku.work/archives/1839</link>
					<comments>https://otonan-syusyoku.work/archives/1839#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Sat, 17 Aug 2024 08:06:12 +0000</pubDate>
				<category><![CDATA[仕事の独り言]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[Laravel]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=1839</guid>

					<description><![CDATA[概要 個人開発で使用している以下スタックで画像を保存できない問題がおきた。 Laravel10 MinIO(S3の代わり) Intervention IMage 3 調査 Intervention IMage Inter [&#8230;]]]></description>
										<content:encoded><![CDATA[<h2>概要</h2>
<p>個人開発で使用している以下スタックで画像を保存できない問題がおきた。</p>
<ul>
<li>Laravel10</li>
<li>MinIO(S3の代わり)</li>
<li>Intervention IMage 3</li>
</ul>
<h2>調査</h2>
<h3>Intervention IMage</h3>
<p>Intervention IMage がVersion2 → Version3 で大きく変わったこともあり、使用法を疑ったが、何ら問題はなかった。</p>
<p>debug等の値を見て見たが、問題なし。。。</p>
<pre class="line-numbers"><code class="language-php">    /**
     * 画像をリサイズする.
     *
     * @param \Illuminate\Http\UploadedFile $file
     * @return \Intervention\Image\Interfaces\ImageInterface
     */
    public function resize(UploadedFile $file): ImageInterface
    {
        return $this-&gt;ImageManager
            -&gt;read($file)
            -&gt;resize(Media::BLOG_IMAGE_WIDTH, Media::BLOG_IMAGE_HEIGHT);
    }


    /**
     * 画像をS3にPutする.
     *
     * @param string $path
     * @param \Illuminate\Http\UploadedFile $file
     * @return bool
     */
    public function putForS3(string $path, UploadedFile $file): bool
    {
        $convertFile = $this-&gt;ImageManger-&gt;resize($file)-&gt;toPng();
        return $this-&gt;diskS3-&gt;put($path, $convertFile);
    }</code></pre>
<h3>minio への通信</h3>
<p>ローカル環境をDockerを用いて開発していることもあり、ローカルネットワークが怪しいと何故か閃いた。</p>
<p>以下のコマンドを用いてネットワークを見たところ、同じネットワーク内に存在していたのでコンテナ間の通信は担保されている様子でした。</p>
<pre class="line-numbers"><code class="language-other">docker network ls
docker network inspect</code></pre>
<p>ただし、 minio に向けた <code>curl</code> コマンドが返ってこないことが分かった。</p>
<h2>原因</h2>
<p>調査を進めていくと、サービス名に対してエンドポイントを指定しないといけないことが分かった。</p>
<pre class="line-numbers"><code class="language-other">minio:
    image: quay.io/minio/minio:RELEASE.2023-01-18T04-36-38Z
    container_name: 'discovery-gem_minio'</code></pre>
<p>今回はminioとして登録していたので、 <code>.env</code> のエンドぽいとの指定が以下の様に設定する必要がありました。</p>
<pre class="line-numbers"><code class="language-other">AWS_ENDPOINT=http:{docker-compose.ymlで指定したport}//minio</code></pre>
<p>たったこれだけのために頭を悩ましたのは悔しすぎる。</p>
<p>&nbsp;</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/1839/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>LaravelにVueコンポーネントをバインドする方法</title>
		<link>https://otonan-syusyoku.work/archives/1720</link>
					<comments>https://otonan-syusyoku.work/archives/1720#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Mon, 15 Apr 2024 14:06:40 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Laravel]]></category>
		<category><![CDATA[SPA]]></category>
		<category><![CDATA[Vue]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=1720</guid>

					<description><![CDATA[Laravelプロジェクトを運用している方が jQuery を卒業して Vue または React を導入したい！という悩みに直面する事はしばしばあると思います。 SPAを構築するのはコスト的に対応が難しいため、Lara [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>Laravelプロジェクトを運用している方が<span class="sc_marker blue"><strong> jQuery を卒業して Vue または React を導入したい！</strong></span>という悩みに直面する事はしばしばあると思います。</p>
<p>SPAを構築するのはコスト的に対応が難しいため、Laravelプロジェクトの一部にVueを導入する方法を解説しまっす。</p>
<h2>環境</h2>
<ul>
<li>PHP8.2</li>
<li>Laravel10</li>
<li>Vue3
<ul>
<li>node v18.19.1</li>
<li>npm 10.5.0</li>
</ul>
</li>
</ul>
<h2>やりたいこと</h2>
<p>Laravel10の一部にVue.jsを適用する</p>
<ul>
<li>Vueコンポーネントを定義する</li>
<li>Vueコンポーネントをバインドする</li>
<li>Vueコンポーネントにバックエンドからデータを渡す</li>
</ul>
<h2>手順</h2>
<p><img decoding="async" src="https://otonan-syusyoku.work/wp-content/uploads/2024/02/Lets-GO.png" alt="Let&#96;s GO" width="1000" height="500" class="aligncenter size-full wp-image-1680" srcset="https://otonan-syusyoku.work/wp-content/uploads/2024/02/Lets-GO.png 1000w, https://otonan-syusyoku.work/wp-content/uploads/2024/02/Lets-GO-300x150.png 300w, https://otonan-syusyoku.work/wp-content/uploads/2024/02/Lets-GO-768x384.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p>
<h3>なにわともあれVueのインストール</h3>
<p>LaravelはビルドツールにViteを採用しているため、ViteのプラグインとしてVueをインストールします。<br />
（CLIでインストールしても良いと思いますよ！</p>
<pre class="line-numbers"><code class="language-other">$ npm install @vitejs/plugin-vue

<span>$ npm install @vitejs/plugin-vue --save-dev</span></code></pre>
<h3>vite.config.js の設定</h3>
<p>インストールしたVueを設定ファイルに追記します</p>
<pre class="line-numbers"><code class="language-js">import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue'; // 追記

export default defineConfig({
  plugins: [vue()] // 追記
});</code></pre>
<h3>app.jsを使える状態に持っていく</h3>
<p>Vueコンポーネントをグローバルコンポーネントとして登録するために、以下の形でapp.jsを編集します。</p>
<p>下記の記述でやりたいこととしては、<span class="sc_marker blue"><strong>コンポーネントの作成及びコンポーネントのマウント</strong></span>です。</p>
<pre class="line-numbers"><code class="language-js">import './bootstrap';
import {createApp} from 'vue';
import Alpine from 'alpinejs';
import VueDatePicker from './Components/Utility/CsrfToken.vue';
import VueDatePicker from './Components/Utility/DatePicker.vue';
import AddSalesListModal from "./Components/AddSalesListModal.vue";

window.Alpine = Alpine;

Alpine.start();

const app = createApp({});

// グローバルコンポーネント
app.component('csrf-token', CsrfToken);
app.component('add-sales-list-modal', AddSalesListModal);
app.component('date-picker', VueDatePicker);

// #appにマウント
app.mount('#app');
</code></pre>
<p>&nbsp;</p>
<h3>マウント先の指定</h3>
<p>app.js でマウント先を id=&#8217;app&#8217; としたため、以下のように blade ファイルにマウント先となる記述を設定します。</p>
<pre class="line-numbers"><code class="language-php">&lt;body id="app" class="font-sans antialiased flex flex-col min-h-screen"&gt;
~
~
~
&lt;/body&gt;</code></pre>
<h3>コンポーネントの作成</h3>
<p>試しにLaravelで生成されるCSRFトークンを扱うコンポーネントを作成します。</p>
<p>このコンポーネントはaxios等で非同期通信を実装するときなどに重宝されるはずですので、皆さんも作っておくと便利ですよん。<br />
（今回は擬似的にpタグにCSRFトークンを出力していますが、本来はしません</p>
<pre class="line-numbers"><code class="language-js">&lt;script&gt;
import { ref, onMounted } from 'vue';

export default function useCsrfToken() {
    const csrfToken = ref('');

    onMounted(() =&gt; {
        const token = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content');
        if (token) {
            csrfToken.value = token;
        }
    });

    return csrfToken;
}
&lt;/script&gt;

&lt;template&gt;
&lt;p&gt;{{ csrfToken }} &lt;/p&gt;
&lt;/template&gt;</code></pre>
<h3>コンポーネントの呼び出し</h3>
<p>以下の通りに記述したらVueで取得したCSRFトークンが出力されているはずですぅぅ</p>
<pre class="line-numbers"><code class="language-php">&lt;csrf-token&gt;&lt;/csrf-token&gt;</code></pre>
<p>Vueにバックエンドのデータを渡したいときには、以下の通りに実装してみてください</p>
<pre class="line-numbers"><code class="language-other">// Blade
&lt;csrf-token :test='@json($test)'&gt;&lt;/csrf-token&gt;

// Vue
&lt;script setup&gt;
import { defineProps, ref } from "vue";

const props = defineProps({
    test: Object,
});
&lt;/script&gt;</code></pre>
<h2>最後に</h2>
<p>SPAカッコいいから時間さえあればSPA化したい。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/1720/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>Larvel10でBreezeのインストールで互換性がないぞと怒られる</title>
		<link>https://otonan-syusyoku.work/archives/1705</link>
					<comments>https://otonan-syusyoku.work/archives/1705#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Sat, 16 Mar 2024 01:24:44 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Laravel]]></category>
		<category><![CDATA[Tips]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=1705</guid>

					<description><![CDATA[公式の手順に則ってBreezeのインストールを行った結果、互換性エラーでインストールできなかったので備忘録がてら残しておきます。 最終的にバージョン指定でインストールしたら動いたっす。。。。 &#160; 環境 PHP  [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>公式の手順に則ってBreezeのインストールを行った結果、互換性エラーでインストールできなかったので備忘録がてら残しておきます。</p>
<p>最終的にバージョン指定でインストールしたら動いたっす。。。。</p>
<p>&nbsp;</p>
<h2>環境</h2>
<ul dir="auto">
<li>PHP 8.2
<ul dir="auto">
<li>Laravel Framework 10.48.3</li>
</ul>
</li>
<li>MySQL 8.0</li>
<li>nginx 1.2</li>
<li>Docker</li>
</ul>
<h2>エラー</h2>
<pre class="line-numbers"><code class="language-php">composer require laravel/breeze --dev
[16-Mar-2024 10:09:35 Asia/Tokyo] Xdebug: [Step Debug] Could not connect to debugging client. Tried: host.docker.internal:9000 (through xdebug.client_host/xdebug.client_port).
Using version ^2.0 for laravel/breeze
./composer.json has been updated
Running composer update laravel/breeze
Loading composer repositories with package information
Updating dependencies
Your requirements could not be resolved to an installable set of packages.

  Problem 1
    - Root composer.json requires laravel/breeze ^2.0 -&gt; satisfiable by laravel/breeze[v2.0.0].
    - laravel/breeze v2.0.0 requires illuminate/console ^11.0 -&gt; found illuminate/console[v11.0.0, ..., v11.0.7] but these were not loaded, likely because it conflicts with another require.

You can also try re-running composer require with an explicit version constraint, e.g. "composer require laravel/breeze:*" to figure out if any version is installable, or "composer require laravel/breeze:^2.1" if you know which you need.

Installation failed, reverting ./composer.json and ./composer.lock to their original content.</code></pre>
<p>&nbsp;</p>
<h2>解消手順</h2>
<h3>インストール可能なVersionを一覧で確認</h3>
<pre class="line-numbers"><code class="language-php">// 実行コマンド
composer show laravel/breeze --all | less</code></pre>
<pre class="line-numbers"><code class="language-php">// 結果
versions : dev-master, 2.x-dev, v2.0.0, 1.x-dev, * v1.29.1, v1.29.0, v1.28.3, v1.28.2, v1.28.1, v1.28.0, v1.27.0, v1.26.3, v1.26.2, v1.26.1, v1.26.0, v1.25.1, v1.25.0, v1.24.1,
 v1.24.0, v1.23.3, v1.23.2, v1.23.1, v1.23.0, v1.22.0, v1.21.2, v1.21.1, v1.21.0, v1.20.2, v1.20.1, v1.20.0, v1.19.2, v1.19.1, v1.19.0, v1.18.2, v1.18.1, v1.18.0, v1.17.0, v1.1
6.1, v1.16.0, v1.15.4, v1.15.3, v1.15.2, v1.15.1, v1.15.0, v1.14.3, v1.14.2, v1.14.1, v1.14.0, v1.13.1, v1.13.0, v1.12.0, v1.11.4, v1.11.3, v1.11.2, v1.11.1, v1.11.0, v1.10.0, 
v1.9.4, v1.9.3, v1.9.2, v1.9.1, v1.9.0, v1.8.2, v1.8.1, v1.8.0, v1.7.3, v1.7.2, v1.7.1, v1.7.0, v1.6.1, v1.6.0, v1.5.0, v1.4.3, v1.4.2, v1.4.1, v1.4.0, v1.3.2, v1.3.1, v1.3.0, 
v1.2.3, v1.2.2, v1.2.1, v1.2.0, v1.1.8, v1.1.7, v1.1.6, v1.1.5, v1.1.4, v1.1.3, v1.1.2, v1.1.1, v1.0.4, v1.0.3, v1.0.2, v1.0.1, v1.0.0, v0.1.0, v0.0.6, v0.0.5, v0.0.4, v0.0.3, 
v0.0.2, v0.0.1, dev-chore/adjusts-workflow, dev-typescript</code></pre>
<p>&nbsp;</p>
<h3>less の結果から1.x 系の最新を選択してインストールする</h3>
<pre class="line-numbers"><code class="language-php">composer require laravel/breeze:^1.29.1 --dev</code></pre>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>めでたしめでたし</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/1705/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>RESTful APIとSPAの関係についてReactとPHPで解説します</title>
		<link>https://otonan-syusyoku.work/archives/1674</link>
					<comments>https://otonan-syusyoku.work/archives/1674#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Sun, 25 Feb 2024 12:40:20 +0000</pubDate>
				<category><![CDATA[好きではないJS]]></category>
		<category><![CDATA[絶対に必要なIT基礎知識]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[JS]]></category>
		<category><![CDATA[Laravel]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[React]]></category>
		<category><![CDATA[Vue]]></category>
		<category><![CDATA[セキュリティ]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=1674</guid>

					<description><![CDATA[RESTful APIとは？ RESTful APIは、ウェブアプリケーションやウェブサービスで使われるプログラミングインターフェースです。 REST（Representational State Transfer）の原 [&#8230;]]]></description>
										<content:encoded><![CDATA[<h2>RESTful APIとは？</h2>
<p><img decoding="async" src="https://otonan-syusyoku.work/wp-content/uploads/2024/02/DMARCを設定しなくちゃ-1.png" alt="What&#96;s up" width="1000" height="500" class="aligncenter size-full wp-image-1665" srcset="https://otonan-syusyoku.work/wp-content/uploads/2024/02/DMARCを設定しなくちゃ-1.png 1000w, https://otonan-syusyoku.work/wp-content/uploads/2024/02/DMARCを設定しなくちゃ-1-300x150.png 300w, https://otonan-syusyoku.work/wp-content/uploads/2024/02/DMARCを設定しなくちゃ-1-768x384.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p>
<p>RESTful APIは、ウェブアプリケーションやウェブサービスで使われるプログラミングインターフェースです。<br />
REST（Representational State Transfer）の原則に基づいて設計されており、ウェブ上のリソースへのアクセスや操作を統一的な方法で提供します。<br />
リソースはURLで識別され、HTTPメソッド（GET、POST、PUT、DELETEなど）を使ってアクセスされます。</p>
<p>[getpost id=&#8221;1672&#8243; cat_name=&#8221;1&#8243; date=&#8221;0&#8243;]</p>
<h2>SPA（シングルページアプリケーション）とは？</h2>
<p>SPAは、ユーザーがアプリケーションを操作する際にページの再読み込みをせずに、必要なデータのみをサーバーから非同期に取得し、動的にページの内容を更新するウェブアプリケーションの形式です。</p>
<p>これにより、<span class="sc_marker blue"><strong>従来のマルチページアプリケーションに比べてユーザーエクスペリエンスが向上します。</strong></span></p>
<p>僕が所属しているチームでも<strong>ページのリロードが嫌だというユーザーの使用感からSPAへの移行が少しづつ始まってきています</strong>。<br />
世間的にもSPAは流行っていますよね。（流行っているから偉いというわけではない。知ることが大事</p>
<h2>RESTful APIとSPAの関係性</h2>
<p><img decoding="async" src="https://otonan-syusyoku.work/wp-content/uploads/2024/02/Lets-GO.png" alt="Let&#96;s GO" width="1000" height="500" class="aligncenter size-full wp-image-1680" srcset="https://otonan-syusyoku.work/wp-content/uploads/2024/02/Lets-GO.png 1000w, https://otonan-syusyoku.work/wp-content/uploads/2024/02/Lets-GO-300x150.png 300w, https://otonan-syusyoku.work/wp-content/uploads/2024/02/Lets-GO-768x384.png 768w" sizes="(max-width: 1000px) 100vw, 1000px" /></p>
<p>SPAでは、<strong>ページの初回読み込み時にアプリケーションの全てのコード（HTML、CSS、JavaScript）がロード</strong>されます。</p>
<p>その後の<span class="sc_marker blue"><strong>ユーザーの操作によってデータが必要になる場合、SPAはRESTful APIを通じてサーバーからデータを非同期に取得</strong></span>します。<br />
<strong>このデータはJSONやXML形式で返され、JavaScriptを用いてクライアントサイドで処理され、ページの一部分だけが動的に更新</strong>されます。</p>
<p>このアーキテクチャにより、SPAはユーザーにスムーズで反応の良いインターフェイスを提供できます。</p>
<p><span class="sc_marker blue"><strong>RESTful APIはこのプロセスの背後にあるデータ通信の基盤となります。</strong></span></p>
<h2>PHPとReactを使った例</h2>
<p>ここでは、PHPで書かれた簡単なRESTful APIと、Reactを使ったSPAの例を示します。</p>
<h3>PHPによるRESTful API</h3>
<p>PHPで簡単なAPIエンドポイントを作成します。この例では、GETリクエストを受け取り、簡単なJSONデータを返します。</p>
<div class="dark bg-gray-950 rounded-md">
<div>
<pre class="line-numbers"><code class="language-php">&lt;?php 
    header('Content-Type: application/json');
    $response = ['message' =&gt; 'Hello, world!'];
    echo json_encode($response); 

<code>    // Response
    //{"message": "Hello, world!"}</code> ?&gt;</code></pre>
</div>
</div>
<p>このPHPスクリプトは、サーバーに配置してのようにアクセスすると<span style="background-color: #ffffff; color: #333333; font-family: 游ゴシック, YuGothic, 'ヒラギノ角ゴ Pro W3', 'Hiragino Kaku Gothic Pro', Verdana, メイリオ, Meiryo, Osaka, 'ＭＳ Ｐゴシック', 'MS PGothic', sans-serif;">JSONが返されます。</span></p>
<h3>ReactによるSPA</h3>
<p>Reactで簡単なSPAを作成し、上記のAPIからデータを取得して表示します。</p>
<div class="dark bg-gray-950 rounded-md">
<div class="p-4 overflow-y-auto">
<pre class="line-numbers"><code class="language-js">import React, { useState, useEffect } from 'react';
import axios from 'axios';

function App() {
  const [message, setMessage] = useState('');

  useEffect(() =&gt; {
    axios.get('http://yourserver.com/index.php')
      .then(response =&gt; {
        setMessage(response.data.message);
      })
      .catch(error =&gt; console.error('There was an error!', error));
  }, []);

  return (
    &lt;div&gt;
      &lt;button&gt;{message}&lt;/button&gt;
    &lt;/div&gt;
  );
}

export default App;
</code></pre>
<p>このコードは、コンポーネントがマウントされた後にAPIからデータを取得し、取得したメッセージを表示します。<br />
React（クライアントサイド）とPHP（サーバーサイド）を使った、RESTful APIとSPAの基本的な連携を示しています。</p>
</div>
<p>今回のコードでは、データを取得して表示するだけのコードになっていますが、Event処理などによりリロードされることなく動的にページの内容を変更させることが可能です。</p>
<h2>セキュリティとパフォーマンスの考慮</h2>
</div>
<p>SPA（シングルページアプリケーション）とRESTful APIを使用する際には、セキュリティとパフォーマンスの両方に配慮することが重要です。<br />
以下では、これらの観点から基本的なガイドラインをいくつか紹介します。</p>
<h3>セキュリティ</h3>
<ol>
<li><strong>HTTPSを使用する<br />
</strong>データの暗号化を確実に行うため、APIとの通信には常にHTTPSを使用します。（当たり前です）<br />
これにより、中間者攻撃（MITM）のリスクを減らすことができます。</li>
<li><strong>CORSポリシーを適切に設定する<br />
</strong>クロスオリジンリソースシェアリング（CORS）ポリシーを適切に設定し、信頼できるオリジンからのリクエストのみを許可します。<br />
不適切なCORS設定は、セキュリティリスクを招く可能性があります。</li>
<li><strong>認証と認可<br />
</strong>JWT（JSON Web Tokens）やOAuthなどの堅牢な認証メカニズムを使用して、APIへのアクセスをセキュアに管理します。<br />
また、ユーザーの権限に基づいてアクセスを制御する認可も重要です。</li>
<li><strong>入力の検証とサニタイズ<br />
</strong> SQLインジェクションやクロスサイトスクリプティング（XSS）攻撃を防ぐため、サーバー側とクライアント側の両方で入力値の検証とサニタイズを行います。</li>
<li><strong>依存関係のセキュリティ<br />
</strong>使用するライブラリやフレームワークのセキュリティ脆弱性に注意し、定期的に更新を行い脆弱性を修正します。</li>
</ol>
<p>この辺の対策については過去に記事にしていますので時間ある人は読んでみてくださーい</p>
<p>[getpost id=&#8221;1618&#8243; cat_name=&#8221;1&#8243; date=&#8221;0&#8243;][getpost id=&#8221;1256&#8243; cat_name=&#8221;1&#8243; date=&#8221;0&#8243;]</p>
<h3>パフォーマンス</h3>
<ol>
<li><strong>コードの分割<br />
</strong>ユーザーが必要とするコードのみをダウンロードするように、コード分割（Code Splitting）を実装します。<br />
これにより、初期ロード時間を短縮できます。</li>
<li><strong>キャッシュ戦略の利用<br />
</strong>静的リソースやAPIレスポンスのキャッシュを適切に利用することで、パフォーマンスを向上させることができます。<br />
ブラウザのキャッシュやCDNの利用が有効です。</li>
<li><strong>遅延ローディング（Lazy Loading）<br />
</strong> 画像やコンポーネントなど、必要になるまでロードしないようにします。<br />
これにより、初期ロードのパフォーマンスを向上させることができます。</li>
<li><strong>APIの最適化<br />
</strong>不必要なデータの送受信を避けるため、APIのレスポンスをできるだけ小さく保ちます。<br />
また、必要なデータのみを取得するためのフィルタリングやページネーションをAPI側でサポートします。</li>
<li><strong>フロントエンドのパフォーマンス最適化<br />
</strong>Reactなどのフロントエンドフレームワークを使用する場合は、不要な再レンダリングを避け、メモ化（memoization）や仮想DOMの効率的な利用などのテクニックを活用します。</li>
</ol>
<p>セキュリティとパフォーマンスは、アプリケーションの設計と開発の初期段階から考慮する必要があります。<br />
これらの基本的なガイドラインを実践することで、ユーザーに安全で快適な体験を提供することができます。</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/1674/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>CORSがわからないからちゃんと勉強してみた</title>
		<link>https://otonan-syusyoku.work/archives/1618</link>
					<comments>https://otonan-syusyoku.work/archives/1618#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Sun, 28 Jan 2024 06:53:06 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[HTTP]]></category>
		<category><![CDATA[Laravel]]></category>
		<category><![CDATA[MDN]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=1618</guid>

					<description><![CDATA[こんにちは！今日は、Web開発でよく聞くけど意外と理解しづらいCORS（Cross-Origin Resource Sharing）について、一緒に学んでいこうと思います。 Webの世界は複雑で、ちょっとしたことが大きな [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>こんにちは！今日は、Web開発でよく聞くけど意外と理解しづらい<strong>CORS（Cross-Origin Resource Sharing）</strong>について、一緒に学んでいこうと思います。</p>
<p>Webの世界は複雑で、ちょっとしたことが大きな違いを生むんですよね。CORSもその一つ。</p>
<p>さあ、一緒にCORSを理解してきましょう〜</p>
<h2>CORSって何？</h2>
<p>まず、CORSって何？って話から始めます。</p>
<p>CORSは、Webページが異なるオリジン（つまり、異なるドメイン、プロトコル、またはポート）のリソースにアクセスする際のセキュリティメカニズムです。</p>
<p>つまり、あなたのサイトが他のサイトのデータを安全に扱うためのルールのこと。これがないと、セキュリティリスクが高まります。</p>
<table style="border-collapse: collapse; width: 100%;">
<tbody>
<tr style="background-color: #7ab1f0;">
<td style="width: 50%;"></td>
<td style="width: 50%;"></td>
</tr>
<tr>
<td style="width: 50%;">ホスト (Host)</td>
<td style="width: 50%;">インターネット上で情報やリソースを提供するコンピューターやサーバー。各ホストには独自のIPアドレスがあり、インターネット上で特定の位置を持つ。</p>
<p>例：ウェブサイトをホストするサーバー</td>
</tr>
<tr>
<td style="width: 50%;">ドメイン (Domain)</td>
<td style="width: 50%;">インターネット上のアドレスの一部。ウェブサイトや電子メールアドレスを識別するために使われる。人間が理解しやすい形式でサーバーを識別するために用いられる。</p>
<p>例：「example.com」</td>
</tr>
<tr>
<td style="width: 50%;">オリジン (Origin)</td>
<td style="width: 50%;">ウェブページの起源を示す概念。スキーム（プロトコル）、ホスト（ドメイン名）、ポートの組み合わせで定義される。</p>
<p>例：「https://example.com:80」</td>
</tr>
</tbody>
</table>
<h2>なぜCORSが必要なの？</h2>
<p>Webはオープンでつながっているけど、同時にセキュリティも重要です。</p>
<p>例えば、あなたがログインしているサイトAから、悪意のあるサイトBがデータを盗もうとするといったリスクがあります。</p>
<p>CORSは、このような不正なアクセスを防ぐために存在しているんです。<br />
安全なWebのためには、必要不可欠なんですよ。</p>
<h2>CORSの仕組み</h2>
<p>CORSの基本は<span class="sc_marker blue"><strong>「信頼できるオリジンからのリクエストのみ許可する」</strong></span>ということ。</p>
<p>これは、サーバー側で設定され、ブラウザがこの設定に従います。</p>
<p>サーバーは、リクエストが来たときに「このオリジンからのリクエストはOKかな？」とチェック。</p>
<p>OKならリソースを提供し、ダメなら拒否。これで、安全にデータのやりとりができるようになります。</p>
<h3>簡単なCORSの例</h3>
<p>例えば、あなたのサイト（example.com）が、他のサイト（api.example.com）からデータを取得したい場合があるとします。</p>
<p>もし、api.example.comがCORSでexample.comを許可していれば、問題なくデータのやりとりができます。</p>
<p>でも、許可されていなければ、「CORSエラー」が発生してアクセスできないんです。</p>
<h3>CORSをどう扱う？</h3>
<p>開発者としては、CORSは頭痛の種になることも。</p>
<p>しかし、適切に設定することでセキュリティを確保しつつ、必要なデータ交換も可能になります。サーバーの設定を見直したり、必要に応じてオリジンを許可リストに追加することが大切です。</p>
<h2>設定方法</h2>
<h3>素のPHP</h3>
<p>※WEBサーバーにて設定することも可能ですが、今回はPHPでの実装を想定。</p>
<pre class="line-numbers"><code class="language-php">header("Access-Control-Allow-Origin: http://example.com");
header("Access-Control-Allow-Methods: GET, POST, PUT, DELETE");
header("Access-Control-Allow-Headers: Content-Type, X-Requested-With");

/**
* - http://example.com からのアクセスを許可
* - 許可メソッドは GET, POST, PUT, DELETE
* - <span>リクエスト中に許可されるHTTPヘッダー
*     - Content-Type（リソースのメディアタイプ
*     - X-Requested-With（通常、Ajaxリクエストを識別するために使用される）
*/</span></code></pre>
<h3>Laravel</h3>
<p>※<span>Laravel 7.x以降ではデフォルトでCORS設定が組み込まれているっぽい。</span></p>
<pre class="line-numbers"><code class="language-php">return [
    'paths' =&gt; ['api/*'],
    'allowed_methods' =&gt; ['*'],
    'allowed_origins' =&gt; ['http://example.com'],
    'allowed_origins_patterns' =&gt; [],
    'allowed_headers' =&gt; ['*'],
    'exposed_headers' =&gt; [],
    'max_age' =&gt; 0,
    'supports_credentials' =&gt; false,

    /**
     * - http://example.com からのアクセスを許可
     *   'allowed_origins' =&gt; ['http://example.com']
     *   この設定は、http://example.com からのリクエストを許可します。
     * 
     * - 許可されるHTTPメソッド
     *   'allowed_methods' =&gt; ['*']
     *   この設定は、すべてのHTTPメソッドを許可します。特定のメソッドのみを許可する場合は、
     *   ['GET', 'POST', 'PUT', 'DELETE'] のように配列を編集します。
     * 
     * - 許可されるHTTPヘッダー
     *   'allowed_headers' =&gt; ['*']
     *   この設定は、すべてのHTTPヘッダーを許可します。特定のヘッダーのみを許可する場合は、
     *   必要なヘッダーを配列に追加します。
     */
];
</code></pre>
<p>&nbsp;</p>
<h2>まとめ</h2>
<p>CORSは、Webの安全性を保つための重要なメカニズム。最初は複雑に感じるかもしれませんが、基本を理解すれば、より安全で効果的なWebアプリケーション開発が可能になります。</p>
<p>これにてCORSの基本を何となく理解！</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/1618/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>自分で作ったサービスで売上を上げるのめちゃくちゃ難しいやんけ</title>
		<link>https://otonan-syusyoku.work/archives/1613</link>
					<comments>https://otonan-syusyoku.work/archives/1613#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Sat, 27 Jan 2024 01:55:46 +0000</pubDate>
				<category><![CDATA[仕事の独り言]]></category>
		<category><![CDATA[日々の独り言]]></category>
		<category><![CDATA[生涯独学]]></category>
		<category><![CDATA[AWS]]></category>
		<category><![CDATA[Docker]]></category>
		<category><![CDATA[LAMP]]></category>
		<category><![CDATA[Laravel]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[個人開発]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=1613</guid>

					<description><![CDATA[こんにちは。都内でPHPerとして勤務している三流プログラマーです。 本業とは別に取り組んでいた個人開発でマネタイズができず、サービスを終了させてしまったのでここで供養させてください。 RIP My Service&#8 [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>こんにちは。都内でPHPerとして勤務している三流プログラマーです。</p>
<p>本業とは別に取り組んでいた個人開発でマネタイズができず、サービスを終了させてしまったのでここで供養させてください。</p>
<p>RIP My Service&#8230;</p>
<h2>作ったもの</h2>
<p>HP 兼 予約サイト 兼 ECサイトなるシステムを開発しました。</p>
<p>僕が沖縄県出身ということもあり、沖縄の個人経営を営んでいる小さな企業さんを相手に営業の肩代わりをすることを目的にシステムを開発しました。</p>
<p>というのも沖縄県は観光地として有名でありながらもHPすら持たず、地元の口コミのみで経営を行っているお店が多々ある状態でした。</p>
<p>せっかくの観光地でありながらお客様を呼び込めないのはかなりもったいないという思いから作った次第でございます。</p>
<h2>技術構成</h2>
<table style="border-collapse: collapse; width: 100%;">
<tbody>
<tr>
<td style="width: 50%;">デザイン</td>
<td style="width: 50%;">Tailwind + DaisyUI</td>
</tr>
<tr>
<td style="width: 50%;">フロントエンド</td>
<td style="width: 50%;">React</td>
</tr>
<tr>
<td style="width: 50%;">バックエンド</td>
<td style="width: 50%;">Laravel10</td>
</tr>
<tr>
<td style="width: 50%;">DB</td>
<td style="width: 50%;">RDS(MySQL8.x)</td>
</tr>
<tr>
<td style="width: 50%;">決済</td>
<td style="width: 50%;">Stripe</td>
</tr>
<tr>
<td style="width: 50%;">インフラ</td>
<td style="width: 50%;">サーバー：EC2<br />
DB：RDS<br />
ファイルサーバー：S3</td>
</tr>
<tr>
<td style="width: 50%;">その他</td>
<td style="width: 50%;">Docker</td>
</tr>
</tbody>
</table>
<h2>マネタイズポイント</h2>
<h3>物販購入</h3>
<p>沖縄ならではの商品が展開されるEC機能を開発しました。</p>
<p>1商品当たり個別に x％ の手数料をいただく契約になります。</p>
<h3>予約</h3>
<p>美容院やレジャー施設の予約を受け付ける機能を開発しました。</p>
<p>こちらもEC同様に1予約あたり、x円の手数料 or オプション契約 のどちらかを契約する想定でした。</p>
<h2>売り方</h2>
<p>沖縄出身ではあるものの都内で勤務しているということもあり現地での営業活動ができないという状況でした。<br />
そのため、現地で営業活動を行ってもらうために地元の友だちに「俺はこれから月100万円稼ぐシステムを開発するから営業をしてくれ」と<strong>大きく誇張した言い分</strong>を持って営業活動をしてもらいました。</p>
<p>その友人は面白そうだからという理由で快く引き受けてくれ、以下のマーケティング手法で営業を行ってもらいました。</p>
<ul>
<li>SNS
<ul>
<li>Instagram</li>
<li>Twitter</li>
</ul>
</li>
<li>ブログ</li>
</ul>
<p>先に結論から入るのですが、期間としては6ヶ月間行ってもらい、皆さんの想像通り契約は1件も入らなかったです。</p>
<h2>なぜ売れなかったのか</h2>
<h3>知名度</h3>
<p>これは誰しもが考えることだと思うのですが <span class="sc_marker blue"><strong>認知されていないサービスにお金を払う</strong></span> ことは避けたいはずです。</p>
<p>尚更、登記もしていない<span class="sc_marker blue"><strong>個人が開発したシステムに対して自分の命であるお金を注ぐことはあり得ない</strong></span>です。</p>
<p>考えられる手法としては以下の手法が取れるはずです。</p>
<ul>
<li>正しい営業をする</li>
<li>受託等で知名度を得る</li>
<li>その他のサービスで知名度を得る（知名度が無いことによる無限ループが発生する…）</li>
</ul>
<p>お客様が安心してこのサービスにはお金を投資できると胸を張って言えるようなシステムを構築するのは難しいですね。。。</p>
<h3>効果を得られるか不安</h3>
<p>知名度がないという理由にも近しいですが、当システムを使用することで利益を得られることに対する不安を拭い去る事はできませんでした。</p>
<p>なぜなら<span class="sc_marker blue"><strong>契約が1件もないということは実績が無いということですからお客様からすると不安しかありません</strong></span>。</p>
<p>世の中のスタートアップはどうやって利益を得ているんですか？？</p>
<h3>県民性</h3>
<p>こちらは確固たるデータがある訳ではないんですが、ハードに仕事をしないという県民性を見誤っていた可能性がある事を感じています。</p>
<p>沖縄は「のんかーな性格（のんきな性格）」と呼ばれる人が多い印象です。</p>
<p>事実として僕の知っている<span class="sc_marker blue"><strong>沖縄の経営者では食べていける分を稼げて楽しい毎日を送ることが大切</strong></span>という人が多いです。（4人だけしか知りませんが…）</p>
<p>そういった考えを持っている人に対して業務を効率化して売上を伸ばしましょうなんて言っても「忙しくなるなら現状のままで」といった答えが返ってくるに決まっています。</p>
<p>そのあたりをしっかりと調査する or ターゲットを先に見つける事が大切かなぁという印象です。</p>
<h2>反省</h2>
<p>僕はゴミを作ってしましました。</p>
<p>誰にも使われないシステムなんてゴミです。ただのゴミクズです。</p>
<p>今回は僕一人と頭の悪い友人の時間だけが溶けただけで済んで本当に良かったです。（実際には5万ほど運用費としてお金を使いました。）</p>
<p>仮に起業という形でサービスを開発していた場合は廃業に大きく近づいていたので、個人開発の一環でここまでの勉強ができたのは僕の才能かもしれません。笑</p>
<p>まだまだ作りたいものはあるので引き続き頑張っていきたいですねぇ〜</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/1613/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
		<item>
		<title>【Exif削除】PHPで写真から「余計な情報」を消す方法をマスターしよう</title>
		<link>https://otonan-syusyoku.work/archives/1611</link>
					<comments>https://otonan-syusyoku.work/archives/1611#respond</comments>
		
		<dc:creator><![CDATA[hrokig2]]></dc:creator>
		<pubDate>Sun, 21 Jan 2024 08:00:49 +0000</pubDate>
				<category><![CDATA[PHP]]></category>
		<category><![CDATA[Laravel]]></category>
		<category><![CDATA[Tips]]></category>
		<guid isPermaLink="false">https://otonan-syusyoku.work/?p=1611</guid>

					<description><![CDATA[PHPエンジニアのみなさん、こんにちは！ 今日はPHPで写真からExifデータを取り除く方法について、わかりやすく解説していこうと思います。知ってると便利な小技ですよ。 Exifデータって何？ Exifデータって、デジタ [&#8230;]]]></description>
										<content:encoded><![CDATA[<p>PHPエンジニアのみなさん、こんにちは！<br />
今日はPHPで写真からExifデータを取り除く方法について、わかりやすく解説していこうと思います。知ってると便利な小技ですよ。</p>
<h2>Exifデータって何？</h2>
<p>Exifデータって、デジタル写真に含まれる「隠れた情報」のこと。<br />
これには撮影日時や場所、使われたカメラの設定などが含まれています。</p>
<p>便利な情報なんだけど、これが原因でプライバシーが漏れることも。だから、写真をネットにアップする前には、このExifデータを削除しておくのが安全策なんです。</p>
<p>[getpost id=&#8221;1608&#8243; cat_name=&#8221;1&#8243; date=&#8221;0&#8243;]</p>
<h2>PHPでExifデータを消すには？</h2>
<p>さて、PHPでExifデータを削除する方法ですが、意外と簡単にできます。</p>
<p>まずは、GDライブラリを使います。<br />
これはPHPで画像を処理する際によく使われるライブラリです。<br />
以下のようなコードでExifデータを削除できますよ。</p>
<pre class="line-numbers"><code class="language-php">&lt;?php
$image = imagecreatefromjpeg('example.jpg'); // JPEG画像を読み込む
imagejpeg($image, 'result.jpg'); // 画像を保存することでExifデータを削除
imagedestroy($image); // メモリを解放
?&gt;
</code></pre>
<p>&nbsp;</p>
<p>このコードで何が起きているかというと、imagecreatefromjpeg関数で画像を読み込んで、imagejpeg関数で新しいファイルとして画像を保存しています。</p>
<p>この保存のプロセスで、Exifデータが取り除かれるんですね。</p>
<p>※ imagecreatefromjpeg は楽に確認したく使用しました。使用している技術に合わせて適切なもの使って下さい。</p>
<h2>画質を保ちつつExifを消すコツ</h2>
<p>画質を落とさずにExifデータだけを削除したい場合は、imagejpeg関数の第3引数に画質（0から100）を指定します。100が最高画質です。</p>
<p>この方法で、画像の見た目はそのままに、Exifデータだけを上手く取り除くことができますよ。</p>
<pre class="line-numbers"><code class="language-php">imagejpeg($image, 'result.jpg', 100);</code></pre>
<h2>まとめ</h2>
<p>PHPを使ってExifデータを削除するのは、プライバシー保護のためにも重要です。</p>
<p>サイトやアプリでユーザーから写真を受け取る場合は、この処理を加えることで安心して提供できますね。</p>
<p>みなさんも、ぜひこのテクニックを試してみてください！</p>
]]></content:encoded>
					
					<wfw:commentRss>https://otonan-syusyoku.work/archives/1611/feed</wfw:commentRss>
			<slash:comments>0</slash:comments>
		
		
			</item>
	</channel>
</rss>
