20210911のPHPに関する記事は12件です。

画面遷移せずにformを送信する方法

画面遷移せずにformを送信する方法 formを送信する際にaction属性を自身に返す場合、入力した内容はそのまま表示させておきたいですよね。 <form action="" method="post"> <input type="text" name="name"> <input type="text" name="address"> <input type="submit" value="保存"> </form> 上記の例はaction属性が空なので自身に遷移します。 phpのみで入力した値を保持したい場合はinputのvalue属性にPOSTで渡ってきた情報を出力してやる必要があります。 <?php if(isset($_POST["save"])){ echo "<script>alert('保存しました')</script>"; $name = htmlspecialchars($_POST["name"], ENT_QUOTES); $address = htmlspecialchars($_POST["address"], ENT_QUOTES); } ?> <form action="" method="post"> <input type="text" name="name" value="<?= $name;?>"> <input type="text" name="address" value="<?= $address;?>"> <input type="submit" name="save" value="保存"> </form> 今回の例は入力項目が2つしか無いので作業は少ないですが、入力項目が100個とかになればめんどくささは半端ないです。 そこで私がめんどくささを解消するために使っている方法は以下の通りです。 <?php if(isset($_POST["save"])){ echo "<script>alert('保存しました')</script>"; exit; } ?> <iframe id="iframe" name="iframe" style="display: none;"></iframe> <form action="" method="post" target="iframe"> <input type="text" name="name" value=""> <input type="text" name="address" value=""> <input type="submit" name="save" value="保存"> </form> formの送信先をiframeタグに設定しcssでiframeタグの表示を隠しています。 iframeタグについてはこちら HTML のインラインフレーム要素 <iframe> は、入れ子になった閲覧コンテキストを表現し、現在の HTML ページに他のページを埋め込むことができます。 https://developer.mozilla.org/ja/docs/Web/HTML/Element/iframe <form action="" method="post" target="iframe"> formタグのtarget属性にiframタグのname属性の値を入れてあげます。 そうするとiframタグの中のHTMLがaction属性に指定したPathで読み込まれます。 iframタグの中身が遷移したとしても本体のHTMLは何も変化しませんので、結果として画面遷移せずにformが送信できるといったからくりです。 遷移した先ではphpのプログラムだけ実行したいので余計なHTMLを読み込まないように exit; としてプログラムを終了させています。 画面が遷移しない!!ということは入力した内容もそのままですので、わざわざphpでPOSTの値を取得してechoで出力するといった手間が省けます。 これでめんどくさい作業も省略できますし、表示ミスといった不具合も未然に防ぐことができますね♪
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

最近物忘れのひどい私が書いた、二重登録防止のためにMySQLでロックを使ったPHPのサンプルコード

結論 InnoDBのテーブル トランザクションを開始する SELECT ... FOR UPDATEをする 新規追加もしくは更新のクエリを実行する トランザクションを終了する 概要 1件だけの登録、1件のだけの更新時の処理用 同時登録、同時更新によりデータの整合性が取れなくなる事を防ぐ事が目的 行ロックなのかテーブルロックになってしまうかなどは、考えていない サンプル用テーブル idとnoだけのテーブル。InnoDBである事。 CREATE TABLE test ( id int NOT NULL AUTO_INCREMENT, no int NOT NULL, PRIMARY KEY (id) ) ENGINE=InnoDB; -- 1件入れておく INSERT INTO test (no) VALUES (1); 新規作成 仕様はnoは重複してはならない(ユニークインデックスを貼れば済むが)とします。なので挿入するnoが存在していない事をチェックしてから挿入します。「伝票番号などのnoが重複してはならないという仕様ならユニークインデックス張っておいたら?」と思いますか?思いますよね?私も思うんです。でも世の中にはユニークインデックス使用禁止というシステムが存在するので、存在する事を覚えておいてください。 // 伝票番号など 例)100番 $no = 100; $pdo = new \PDO(略); try { $pdo->beginTransaction(); // ロックを取得する // FOR UPDATEで他のセッションがロックを取得している場合、解除されるまで待つ // FOR UPDATEの後ろにNOWAITを付けている場合、解除されるまで待たずに例外がスローされる $stmt = $pdo->query("SELECT COUNT(*) as cnt FROM test WHERE no = {$no} FOR UPDATE"); // $stmt = $pdo->query("SELECT COUNT(*) as cnt FROM test WHERE no = {$no} FOR UPDATE NOWAIT"); // 3秒以内に別ブラウザで叩いて確認する。FOR UPDATE を付けてないと二重登録されてしまう sleep(3); $r = $stmt->fetch(\PDO::FETCH_OBJ); if (0 < $r->cnt) { echo "<h1>no({$no})のデータが既に存在しています。</h1>"; exit; } // 新規追加 $pdo->exec("INSERT INTO test (no) VALUES ({$no})"); $pdo->commit(); echo '<h1>正常に登録されました</h1>'; } catch (\Exception $e) { $pdo->rollBack(); echo '<h1>エラーが発生しました</h1>'; echo $e->getMessage(); // NOWAITでロックが取得できなかった時の例外メッセージ // SQLSTATE[HY000]: General error: 1205 Lock wait timeout exceeded; try restarting transaction } 更新処理 なんらかの処理が行われたらnoがインクリメントされる処理があるとします。 もし完全に同時に2回行われた時、1回分のインクリメントしかされない事がないようにロックを取得します。 $pdo = new \PDO(略); try { $pdo->beginTransaction(); // idが1のデータのnoをインクリメントするため現在の値を取得 $stmt = $pdo->query('SELECT no FROM test WHERE id = 1 FOR UPDATE'); // $stmt = $pdo->query('SELECT no FROM test WHERE id = 1 FOR UPDATE NOWAIT'); // 3秒以内に別ブラウザで叩いて確認する。FOR UPDATEが入っていないと2回のインクリメントのはずが1回分しか増えない sleep(3); // 値をインクリメントする更新処理 $r = $stmt->fetch(\PDO::FETCH_OBJ); $new_no = $r->no + 1; $pdo->exec("UPDATE test SET no = {$new_no} WHERE id = 1"); $pdo->commit(); echo '<h1>正常に更新されました</h1>'; echo "{$r->no}から{$new_no}へ更新"; } catch (\Exception $e) { $pdo->rollBack(); echo '<h1>エラーが発生しました</h1>'; echo $e->getMessage(); }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel8でバリデーションを日本語化

はじめに  Laravelはログイン機能を簡単に作ることが出来ますが、デフォルトではバリデーションメッセージが英語になっています。日本語に変更することもできますので備忘録として残していきます。 日本語化の手順  Laravelのメッセージファイルはresources/lang/enにあります。enなので英語ですね。ファイルの中身を見てみるとこんな感じです。 resources/lang/en/validation.php <?php return [ /* |-------------------------------------------------------------------------- | Validation Language Lines |-------------------------------------------------------------------------- | | The following language lines contain the default error messages used by | the validator class. Some of these rules have multiple versions such | as the size rules. Feel free to tweak each of these messages here. | */ 'accepted' => 'The :attribute must be accepted.', 'accepted_if' => 'The :attribute must be accepted when :other is :value.', 'active_url' => 'The :attribute is not a valid URL.', 'after' => 'The :attribute must be a date after :date.', 'after_or_equal' => 'The :attribute must be a date after or equal to :date.', 'alpha' => 'The :attribute must only contain letters.', 'alpha_dash' => 'The :attribute must only contain letters, numbers, dashes and underscores.', 'alpha_num' => 'The :attribute must only contain letters and numbers.', 'array' => 'The :attribute must be an array.', 'before' => 'The :attribute must be a date before :date.', 'before_or_equal' => 'The :attribute must be a date before or equal to :date.', 'between' => [ 'numeric' => 'The :attribute must be between :min and :max.', 'file' => 'The :attribute must be between :min and :max kilobytes.', 'string' => 'The :attribute must be between :min and :max characters.', 'array' => 'The :attribute must have between :min and :max items.', ], 'boolean' => 'The :attribute field must be true or false.', 'confirmed' => 'The :attribute confirmation does not match.', 'current_password' => 'The password is incorrect.', 'date' => 'The :attribute is not a valid date.', 'date_equals' => 'The :attribute must be a date equal to :date.', 'date_format' => 'The :attribute does not match the format :format.', 'different' => 'The :attribute and :other must be different.', 'digits' => 'The :attribute must be :digits digits.', 'digits_between' => 'The :attribute must be between :min and :max digits.', 'dimensions' => 'The :attribute has invalid image dimensions.', 'distinct' => 'The :attribute field has a duplicate value.', 'email' => 'The :attribute must be a valid email address.', 'ends_with' => 'The :attribute must end with one of the following: :values.', 'exists' => 'The selected :attribute is invalid.', 'file' => 'The :attribute must be a file.', 'filled' => 'The :attribute field must have a value.', 'gt' => [ 'numeric' => 'The :attribute must be greater than :value.', 'file' => 'The :attribute must be greater than :value kilobytes.', 'string' => 'The :attribute must be greater than :value characters.', 'array' => 'The :attribute must have more than :value items.', ], 'gte' => [ 'numeric' => 'The :attribute must be greater than or equal :value.', 'file' => 'The :attribute must be greater than or equal :value kilobytes.', 'string' => 'The :attribute must be greater than or equal :value characters.', 'array' => 'The :attribute must have :value items or more.', ], 'image' => 'The :attribute must be an image.', 'in' => 'The selected :attribute is invalid.', 'in_array' => 'The :attribute field does not exist in :other.', 'integer' => 'The :attribute must be an integer.', 'ip' => 'The :attribute must be a valid IP address.', 'ipv4' => 'The :attribute must be a valid IPv4 address.', 'ipv6' => 'The :attribute must be a valid IPv6 address.', 'json' => 'The :attribute must be a valid JSON string.', 'lt' => [ 'numeric' => 'The :attribute must be less than :value.', 'file' => 'The :attribute must be less than :value kilobytes.', 'string' => 'The :attribute must be less than :value characters.', 'array' => 'The :attribute must have less than :value items.', ], 'lte' => [ 'numeric' => 'The :attribute must be less than or equal :value.', 'file' => 'The :attribute must be less than or equal :value kilobytes.', 'string' => 'The :attribute must be less than or equal :value characters.', 'array' => 'The :attribute must not have more than :value items.', ], 'max' => [ 'numeric' => 'The :attribute must not be greater than :max.', 'file' => 'The :attribute must not be greater than :max kilobytes.', 'string' => 'The :attribute must not be greater than :max characters.', 'array' => 'The :attribute must not have more than :max items.', ], 'mimes' => 'The :attribute must be a file of type: :values.', 'mimetypes' => 'The :attribute must be a file of type: :values.', 'min' => [ 'numeric' => 'The :attribute must be at least :min.', 'file' => 'The :attribute must be at least :min kilobytes.', 'string' => 'The :attribute must be at least :min characters.', 'array' => 'The :attribute must have at least :min items.', ], 'multiple_of' => 'The :attribute must be a multiple of :value.', 'not_in' => 'The selected :attribute is invalid.', 'not_regex' => 'The :attribute format is invalid.', 'numeric' => 'The :attribute must be a number.', 'password' => 'The password is incorrect.', 'present' => 'The :attribute field must be present.', 'regex' => 'The :attribute format is invalid.', 'required' => 'The :attribute field is required.', 'required_if' => 'The :attribute field is required when :other is :value.', 'required_unless' => 'The :attribute field is required unless :other is in :values.', 'required_with' => 'The :attribute field is required when :values is present.', 'required_with_all' => 'The :attribute field is required when :values are present.', 'required_without' => 'The :attribute field is required when :values is not present.', 'required_without_all' => 'The :attribute field is required when none of :values are present.', 'prohibited' => 'The :attribute field is prohibited.', 'prohibited_if' => 'The :attribute field is prohibited when :other is :value.', 'prohibited_unless' => 'The :attribute field is prohibited unless :other is in :values.', 'prohibits' => 'The :attribute field prohibits :other from being present.', 'same' => 'The :attribute and :other must match.', 'size' => [ 'numeric' => 'The :attribute must be :size.', 'file' => 'The :attribute must be :size kilobytes.', 'string' => 'The :attribute must be :size characters.', 'array' => 'The :attribute must contain :size items.', ], 'starts_with' => 'The :attribute must start with one of the following: :values.', 'string' => 'The :attribute must be a string.', 'timezone' => 'The :attribute must be a valid timezone.', 'unique' => 'The :attribute has already been taken.', 'uploaded' => 'The :attribute failed to upload.', 'url' => 'The :attribute must be a valid URL.', 'uuid' => 'The :attribute must be a valid UUID.', /* |-------------------------------------------------------------------------- | Custom Validation Language Lines |-------------------------------------------------------------------------- | | Here you may specify custom validation messages for attributes using the | convention "attribute.rule" to name the lines. This makes it quick to | specify a specific custom language line for a given attribute rule. | */ 'custom' => [ 'attribute-name' => [ 'rule-name' => 'custom-message', ], ], /* |-------------------------------------------------------------------------- | Custom Validation Attributes |-------------------------------------------------------------------------- | | The following language lines are used to swap our attribute placeholder | with something more reader friendly such as "E-Mail Address" instead | of "email". This simply helps us make our message more expressive. | */ 'attributes' => [], ]; これを日本語に直していく必要があります。 まずはenディレクトリをコピーしてjaディレクトリを作りましょう。そしてja/validation.phpを書き換えていきます。 公式ホームページから日本語のメッセージをコピペできますので丸写ししましょう。 ちなみに、デフォルトではHTMLのinputタグにrequiredと書かれているので、消しておきましょう。 さて、これでバリデーションが日本語化できましたが、まだ少し中途半端です。 nameとかpasswordのように英語が残ってますね。これを変更するためには、validation.phpの最後の方にあるattributesを編集する必要があります。このようにしてみてください。 validation.php 'attributes' => [ 'name' => '名前', 'password' => 'パスワード' ], これで完全に日本語化することができました! まとめ  Laravelすごい!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

WordPress上に、PHPで簡単なウェブアプリを作成する

「WordPress上にウェブアプリを作れないかな~」と考えていたところ、PHPで簡単に作れそうだったので挑戦してみました。 対象者 HTML・CSS・PHPの基礎を理解している人 WordPressがどのような仕組みで動いているのか、ざっくりと理解できている人 WordPressで、すでにブログを運営している人 WordPressを使って、ウェブアプリを作ってみたい人 なお、今回の記事を書くにあたり、こちらの本でPHPとWordPressの仕組みを勉強しました。 WordPressユーザーのためのPHP入門 はじめから、ていねいに。 「PHP以外の言語でコードを書きたい!」という人もいるかもしれませんが、WordPressがPHPをベースとして作成されているため、ある程度の技術が必要になります。 (私は技術力がないので、あきらめました。) 成果物の解説 成果物はこちらになります。 開発環境 今回のウェブアプリは、以下の環境で作成しました。 WordPress 5.8.1 Cocoon childのテーマを使用 ConoHa WING ベーシック(レンタルサーバー) 作成手順 1.WordPressに記事を作成する WordPress管理画面で、投稿 → 新規追加 で、いつもと同様に記事を作成します。 記事の編集画面で、投稿の追加設定から、「URLスラッグ」を設定します。 また、SEOタイトル・記事カテゴリ・アイキャッチ画像を、任意で追加します。 コンテンツ編集画面(左上の枠)には、何も記載しなくてよいです。 また、問題ないかもしれませんが、アイキャッチ画像を設定した場合は、私はこちらのカスタムCSSを追加し、コンテンツ内でアイキャッチ画像が表示されないようにしています。 .eye-catch { display: none; } 2.サーバー内にphpファイルを作成する ConoHa WINGにログインし、ファイルマネージャーをクリックします。 ファイルマネージャー内の「wp-content > themes > cocoon-child」のフォルダへ移動し、single-post-[URLスラッグ].phpというファイルを作成します。 URLスラッグは、手順1でwordpress上で設定したものです。 3.phpファイルにコードを書く 手順2で作成したファイルにコードを書きます。 今回のコードは次の通りです。(慣れていないので、コードが汚い点はご了承ください。) <?php if ( !defined( 'ABSPATH' ) ) exit; if (!is_amp()) { get_header(); } else { get_template_part('tmp/amp-header'); } ?> <!-- 入力フォーム --> <h2>BMI計算アプリ</h2> <p><br></p> <form name="" method="post"> <ul> <li> <p>身長(cm)</p> <input type="number" name="height" size="8" value="<?php echo $_POST["height"] ?>"> <p><br></p> </li> <li> <p>体重(kg)</p> <input type="number" name="weight" size="8" value="<?php echo $_POST["weight"]?>"> <p><br></p> </li> </ul> <div class="wp-block-button has-custom-width wp-block-button__width-50 is-style-fill"> <table> <tr> <input type="submit" name="cal_bottom" value="BMIを計算" style="border-radius:7px"> </tr> </table> </div> <p><br></p> </form> <?php if(isset($_POST["save"])){ $height = htmlspecialchars($_POST["height"], ENT_QUOTES); $weight = htmlspecialchars($_POST["weight"], ENT_QUOTES); } if ($_POST["height"] ==0){ $BMI =0; } else{ $BMI = $_POST["weight"] / pow($_POST["height"]/100,2); } ?> <!-- 計算結果表示 --> <h2>計算結果</h2> <p></p> <p>BMIは、<strong><?php echo round($BMI,2); ?></strong>です。<p> <?php if ($BMI >= 30):?> <p><br>新型コロナウィルスに感染する確率が高いです。<p> <p>引用元:https://www.asahi.com/articles/ASP9876B9P98PTIL023.html</p> <?php endif; ?> <p><br></p> <p>このウェブアプリの作成方法は、<a href="https://corgi-komugi.com/php-test-howto/">こちら</a>から確認できます。 </p> <p><br></p> <?php get_footer(); ?> まとめ WordPress上でウェブアプリを作成すると、既存のStyle.css, hearer, footerが使用できるので、きれいなレイアウトで簡単にウェブアプリを作成することができました。 私のような初心者でも簡単に作成できたので、興味があれば是非試してみてください!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

EC2サーバー構築の概要【備忘録】

はじめに AWSの仮想サーバー構築用クラウドサービス「EC2」を用いて、PHPサイトを立ち上げた時に調べたことのまとめ。 全体の流れ・用語等についての記事であるため、具体的な手順については割愛しています。 目次 全体の流れ 項目別の詳細 用語 参考文献 全体の流れ AWSにサインアップ EC2インスタンスを作成 インスタンスをSSH接続で操作する Apache・PHP・MariaDBをインストール テスト用PHPファイルをアップロード Elastic IPを割り当て 各種設定を変更 項目別の詳細 1. AWSにサインアップ・2. EC2インスタンスを作成  手順通りに進めるだけなので割愛。 3. インスタンスをSSH接続で操作する  作成したインスタンスを操作する際には、端末からSSH接続をする。  SSHクライアントとして、今回はTera Termを使用する。  接続画面ではホストにパブリックDNS、ユーザーにec2-user、認証方式にSSHを選択し、インスタンス作成時に取得した秘密鍵を指定する。 4. Apache・PHP・MariaDBをインストール  Tera Termのターミナル画面からApache、PHP、MariaDBをインストールする。  まずはApacheから。 sudo -i // 管理者権限に切り替え(exitで戻す) yum install httpd //httpd(Apacheの別名)をインストール systemctl start httpd //Apacheを起動 systemctl status httpd //動作状況を確認  続いてPHP。 yum install php //PHPをインストール sudo chown -R ec2-user /var/www/html //指定されたDirの所有者をユーザーに変更 //RオプションでDir下のすべてを変更できる  MariaDB。 yum install mariadb mariadb-server //MariaDBをインストール systemctl start mariadb //起動、こちらもstatusで状態を確認できる 5. テスト用PHPファイルをアップロード  お馴染みのindex.phpでハローワールドを出力してみる。 index.php <?php echo "Hello, World.";  指定ホストにアクセスしてちゃんと画面に出力されれば成功。 6. Elastic IPを割り当て  インスタンスに割り当てられたパブリックIP,パブリックDNSなどは、定期的に行われる再起動によって変動する。その度にAWSコンソールに行ってホストをコピペするのは非合理的なので、その変動を吸収するためのElastic IPというものを設定する。  インスタンスに紐づけることで、そのElastic IPからのアクセスが可能になり、IPが固定化される。  なお、使用料金は紐づけたインスタンスが稼働している間は発生しない。細かい手順は割愛。 7. 各種設定を変更  最期に、実際に開発をするにあたり必要な機能や設定を変更する。 インスタンス再起動時、ApacheとMariaDBを自動で起動するように設定 TeraTerm systemctl enable httpd systemctl enable mariadb データベース設定 MariaDB update mysql.user set password=password('新しいパスワード') where user='ユーザー'; //ユーザーのパスワードを設定 grant all privileges on データベース.*to ユーザー@ホスト; //データベース内の全テーブルへのアクセス権を付与 flush privileges; //設定変更を反映 PDO使用設定  デフォルトではPDOの設定が有効化されていないため、そのままPDOを使おうとするとエラーが出る。 TeraTerm sudo yum install php-pdo //pdo.soをインストール sudo yum install php-mysql //mysqlのドライバをインストール php.ini extension=pdo.so //追加 extension=pdo_mysql.so //追加 用語  導入する中で様々な用語に出くわしたので、その備忘録。 リージョン 「地域」。物理サーバーの設置場所を指す。 AMI(Amazon Machine Image)  サーバー構築用のソフトウェア(OS,サーバーアプリなど)のセット。 EBS(Elastic Block Store)  インスタンスの内部ストレージ。HDDのようなもの。 VPC(Virtual Private Cloud)  利用者ごとに与えられる、仮想ネットワーク空間。 yum  UNIX系のパッケージ管理コマンド。 セキュリティグループ  EC2インスタンス内に適用できるAWSのファイアウォール。 IAMユーザー  IAM(AWSサービスへのアクセスを認可できるサービス)で設定されたユーザー。 参考文献 AWS EC2(Amazon Linux)にPHP7.4をインストール AWS EC2上にPHPサイトを立ち上げて、独自ドメインでアクセスできるようにするまでの全手順 Elastic IPの設定
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

REST API のレスポンス速度を改善するために行なった設計の上で大切なこと

はじめに 社内のプロジェクトで、大量のデータをjsonで返すAPIを実装した際に、レスポンス速度が遅くなりすぎるという課題が発生したことがありました。 この、課題を解決する過程で、開発者がWebサービスを実装する上で意識した方が良い点をいくつか学んだので記事にまとめたいと思います。 for 分のネストを浅くする まず、以下のソースコードを見てください。 api.php $all_datas = $this->model->find($query); foreach($all_datas as $data){ foreach($data['data'] as $value_type => $data_by_type){ foreach($data_by_type as $timestamp => $val){ $response_array[$timestamp] = $val; } } } このようにfor分のネストが深くなると、OSのメモリ上にデータを格納した状態が長く続き、サーバーに大きな負荷がかかってしまいます。 また、ループが何十にも回るせいで非常に大量の回数が回ることになり、このループを抜けるのに非常に時間がかかってしまいます。 対策 for文のネストは極力浅くする必要がありますし、連想配列を使用してデータを作成する際にも、for文のネストが深くならないようにデータ構造を設計してやる必要があります。 場合によっては、DBの設計についても考慮して、API側でデータを扱う際に、使用しやすい形式でDB保存を行う必要もあるかもしれません。 DBに投げるクエリを工夫する 以下のソースコードを見てください。 foreach($user_data as $user_info){ $user_id = $user_info['id']; $data = $this->model->find($user_id); } for分の中で何回もDBへの検索を行なっていると、DBへの検索処理を行うたびに時間がロスしてしまいます。 また、DBへの負荷もかかる。 対処法 改善したソースコード foreach($user_data as $user_info){ $user_id = $user_info['id']; $user_id_list[] = $user_id; } $data = $this->model->find($user_id_list); 1回のクエリでデータをまるっと取得できるようにしてやると良いかなと思います。 未使用変数及び無駄な変数は減らす 未使用変数や無駄な変数が残っていると、以下のような問題点があるかなと思います。 * ソースコードの可読性が落ちる。 * メモリ上に無駄なメモリ領域が確保されてしまう。 PHP関数内の変数について PHPでは関数内で定義された変数は、関数の処理終了時にメモリが開放されるようです。 for文のネストが深く、かつループ分の中で変数に値を代入する際には、適宜変数を初期化してやることで意図しない値が代入されることを防いだり、余分なメモリ領域を確保したままループが回り続けるという現象も防げるのかなと思います。 対処法 この辺りはLinterのルールの中に、未使用変数の残存をチェックするルールを追加して、チーム内で共通で使用するようにすれば、解消できるかなと思います。 また、CI上でLinterを実行するようにしておけば、GithubやGitlab上でコードレビューを行う際に事前にチェックができるかなと思います。 jsonのsizeを軽くする json内部のデータを見直す jsonのデータの中に不要なデータが多く含まれていると、サーバーからクライアントにjsonを送信する際に無駄な時間がかかってしまいます。 大量のデータを扱っている際には、無駄なデータが含まれているせいで数MB単位でデータが肥大化してしまうこともあるので注意が必要ですね。 nginxでデータを圧縮する nginxの設定でjsonデータを圧縮することでデータを軽くすることができます。 サーバー側の対策 swapを使用する swap領域を確保してやることで、物理メモリが圧迫された時にバッファを持たせることができます。 ただし、swap領域を確保する際にサーバーのハードディスクを必要とするため、容量に余裕を持たせておく必要があります。 バッチ処理を作成する あらかじめデータを整形したり、計算しておくことで、API内部の処理を減らすことができるようになり、レスポンス速度が改善できる可能性があります。 もし、仮にバッチ処理を挟まずに、webアプリ側のmodel等で処理を実行させると、ネストの深いfor分が複数あった場合には、サーバーに負荷がかかりますし、APIのレスポンス速度も著しく悪化してしまいます。 Redisの使用を検討する redisを使用してキャッシュを効かせることでDBへのアクセスを減らすことが期待できます。 ただし、redisを使用する際にはキャッシュがOSのメモリ上に保存されるため、サーバーのメモリについても考慮する必要があります。 laravelではデフォルトでSession及びCacheの保存先がstorageディレクトリ内に保存されるため、長期間運用をしているとstorageディレクトリが肥大化し、OS上のストレージを圧迫してしまいます。 サービスのアクセス数が少ないうちは大きな問題にならないかもしれませんが、実運用を考えると早めにRedisを使用する必要があるでしょう。 redisを導入する際にはこちらの記事を参考にしてください。 https://qiita.com/takuyanagai0213/items/2e4fe3fafcb99cb1a10e
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

はじめてのDocker compose

はじめに 以下のような構成で記事を執筆していますが、 どこからでも読めるような構成になっています。 ゼロから始めるDocker入門 はじめてのDockerfile はじめてのDocker compose ←今回はここ 対象読者 Docker の使用に慣れてきた方 docker-compose.yml でなにをしているのか知りたい方 目次 はじめに 対象読者 目次 Docker Composeとは Docker compose ディレクトリ構造 docker-compose.yml Dockerfile Compose コマンド おわりに 参考文献 Docker Composeとは docker-compose.yml という yml 形式のファイルに 複数のコンテナを定義し実行することができるツールです。 Docker compose どのように書いていくのか確認していきます。 (※ 最低限の設計です) ディレクトリ構造 . ├── docker │ └── Dockerfile └── docker-compose.yml docker-compose.yml docker-compose.yml # バージョンの指定 version: '3.9' # サービス定義 services: app: # サービス名(コンテナ名) build: # build context: . # build context dockerfile: docker/Dockerfile # Dockerfile の指定 ports: # port指定(ホストのポートをコンテナのポートにつなげる) # host:container - "8000:80" volumes: # マウント(ファイルシステムの共有) # host:container - '.:/var/www/html' Dockerfile docker/Dockerfile # php のイメージ FROM php:7.4-fpm # コマンド実行ディレクトリ WORKDIR /var/www/html # パッケージインストール RUN apt-get update \ && apt-get install -y libonig-dev libzip-dev unzip Compose コマンド 使用頻度の高いコマンドです。  コマンド 意味 docker-compose build コンテナをbuildする docker-compose up -d デタッチドモードで立ち上げ docker-compose stop 実行中のコンテナを停止 docker-compose down 実行中のコンテナを停止し削除 docker-compose restart コンテナを再起動 docker-compose exec [サービス名(コンテナ名)] [command(bash)] コンテナに対しコマンド実行。bashを書くとコンテナ内に入ることができる。 おわりに 今回3部構成で記事を執筆いたしました。 すべて読みすすめたら Docker に対して困ることは少なくなるのかなと思います。 もちろんすべてを網羅したわけではないですし、説明不足な点もあるかもしれませんが、 「Dockerって何?」 というところから抜け出すきっかけになりましたら幸いです。 記事で足りない点は調べて補いつつ、さらに理解を深めたいときは 教材など購入、公式ドキュメントなど読みながら手を動かしてみると深く学ぶことができるのではないでしょうか。 参考文献 Docker Compose docker と docker-compose の初歩 Docker compose ことはじめハンズオン マウント (mount)
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Eclipse(Xampp)のワークスペースをhtdocs以外にしようとして苦労した話

はじめに Eclipse(Xampp)でも大抵の場合、htdocsにファイルを置いておけばローカルではたいてい動く。 ここまでは下記の記事でできた。 だが、仕事の都合上、htdocs以外の別の場所におかないといけなくなった。 そんなわけで、上の記事で保留した「別の場所に設定できない問題」というのを 解決せざるを得なくなった。 というわけであれこれ試行錯誤した結果をまとめたい。 1. ファイルを置きたい場所に移動させて、パスを取得する まずは今までhtdocsで作ったファイル群を置きたい場所に移動させておく。 ここでは仮に「C:¥MyPHPTool¥」に移動させるとする。 2. Eclipseを開き、最初のワークスペースを決めるところで、上記のパスを入れる 元のhtdocsの場合、C:¥¥xampp¥htdocsとか、 Eclipse入れてたら C:¥¥Eclipse¥xmapp¥htdocs だけど、 置きたい場所の C:¥¥MyPHPTool を入れる。 (Macの場合は読み替えてください)  →あとでMacでもしてみて変更します(自分の勉強のため) 3. xamppのコントロールパネルのConfigからhttpd.confでもドキュメントルートを変更 DocumentRootで検索すると1箇所見つかり、 最初は httpd.conf DocumentRoot "C:¥¥xampp¥htdocs"  というのがあり、ここを C:¥¥MyPHPTool に変える。 その下の方に (Directoryで検索するといいかも) httpd.conf <Directory "C:¥¥xampp¥htdocs"> ... </Directory> というのがあり、ここも C:¥¥MyPHPTool に変えて保存 XamppのApacheををStopしてStart(再起動)。 念の為Eclipseもクリーンして閉じて再度開く。 そしてWebアプリケーション実行で何らかのファイルを実行してみると、 成功します。 4. 参考 ここは逆にhtdocsに変更する感じだけど 逆に読み替えて成功しました。 ありがとうございました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】Non-static method <メソッド名> should not be called staticallyの解決方法

事象 以下のようにメソッドを呼び出したときに発生します。 class Item extends Model { public function getItems() { // 取得処理 class ItemController extends Controller { public function index(Request $request) { $items = Item::getItems(); // Error > Non-static method App\Models\Item::getItems() should not be called statically 原因 エラーメッセージを訳すと「非静的メソッドApp\Models\Item::getItems()は静的に呼び出されるべきではありません」になります。 原因はそのままでgetItemsは非静的メソッドなので、静的な呼び出しを行なってはならない、ということになります。 「静的」とは? クラスのメソッドを静的として宣言すると、クラスのインスタンス化を必要とせずにそれらにアクセスできるようになります。 「静的な呼び出し」とは? クラス名::メソッド名()のような書き方です。 静的呼び出しではItemクラスのインスタンスを作成せずにgetItemsメソッドを呼び出しています。 上記の例ではgetItemsは静的なメソッドとして定義されていないので、呼び出すにはインスタンスを生成する必要があります。それを静的呼び出し(インスタンスを生成せず呼び出す方法)で呼び出そうとしているので警告されているわけですね。 解決方法 1.インスタンスを生成し、インスタンスメソッドとして呼び出す getItemsは非静的メソッドなので静的な呼び出しを行ってはならない、ということだったのでインスタンスを作成して、インスタンスメソッドとして呼び出すようにします。 class ItemController extends Controller { public function index(Request $request) { $i = new Item(); // Itemクラスのインスタンスを生成 $items = $i->getItems(); //生成したItemインスタンスのgetItemsメソッドを呼び出す 2.静的メソッドに変更する getItemsは非静的メソッドなので静的な呼び出しを行ってはならない、ということだったのでgetItemsを静的メソッドに変更してあげます。 class Item extends Model { public static function getItems() // メソッド名にstaticキーワードを付けると静的メソッドになる { どちらを使えばいいのか? インスタンスメソッド インスタンスごとに異なる動作を期待する場合 静的メソッド いろんな場所で繰り返し同じ処理を呼びたい場合 呼び出す場所によって期待する動作が異ならない(常に同じものを返してほしい)場合 参考 Why I'm getting 'Non-static method should not be called statically' when invoking a method in a Eloquent model? PHPでなくC#ですが、静的メンバ―の説明がわかりやすかったので。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

SESAME3 Web APIの開閉操作をPHPで実装してみた

candyhouse公式のドキュメントではPHPでの実装方法が見つからなくて色々苦心したので記事にまとめてみました 使用環境 PHP 7.3.22 使用ライブラリ cryptlib/cmac dev-master(2021/09/11時点) 手順 まずはAPI使用に必要な情報をSESAMEのシェア用QR(オーナー権限)から取得 公式だと手順が面倒くさかったけれど、便利なツールがあったのでこれを使用 使うのは以下の項目 UUID Secret Key 次に、SESAMEのデベロッパーサイトにログインしてAPI_KEYを取得 実装 AES-CMAC をPHPで実装してある記事が見つからなかったので、試行錯誤の結果です 基本的には公式ドキュメントのJSとPythonの実装を足して、PHPのライブラリの仕様に沿わせた感じです use CryptLib\MAC\Implementation\CMAC; define('SCRET_KEY', '****') define('API_KEY', '****') define('UUID', '****') // 履歴に残る名前。半角しか使えないらしい $history = base64_encode('WEB API'); // 操作コマンド $cmd = 88; // toggle:88/lock:82/unlock:83 $hasher = new CMAC(); $key = hex2bin(SECRET_KEY); $time = strtotime(date("Y/m/d H:i:s")); // big endianでバイナリ化されていたので、反転してlittle endianに変換 $msg = substr(strrev(hex2bin(dechex($time))), 1); $sign = bin2hex($hasher->generate($msg, $key)); $data = compact('cmd', 'history', 'sign')); $url = "https://app.candyhouse.co/api/sesame2/" . UUID . "/cmd"; $method = 'POST'; $header = [ "Content-Type: application/json", "x-api-key: " . API_KEY ]; $content = json_encode($data); $options = [ 'http' => compact('method', 'header', 'content') ]; echo file_get_contents($url, false, stream_context_create($options)); 備忘録として書いたのでわかりずらいところもあるかと思いますが、誰かの参考になれば。。 CMACのところとか、もっといい書き方やご指摘、不明点などあればコメントください!!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP selenium(facebook/webdriver)を使ってみよう

はじめに PHPで、seleniumを使用したい人 自動化処理に興味がある方 seleniumとは Selenium は、 Webアプリケーションをテストするためのポータブルフレームワークである。 Selenium は、テストスクリプト言語(Selenium IDE)を学ぶ必要なしに、機能テストを作成するための再生ツールを提供する。 出典: フリー百科事典『ウィキペディア(Wikipedia)』 ChromeDriverをインストール ChromeDriverは、Chromeを動かすために必要なドライバーになります。 こちらからダウンロード macの場合はHomeBrewでインストール可能 コマンド: brew install chromedriver selenium-server-standaloneをインストール Windowsはこちらからダウンロード macの場合はHomeBrewでインストール可能 コマンド: brew install selenium-server-standalone Composerのインストール Composerは、PHPのライブラリ管理ツールです。 ※今回は、php-webdriverを使用し管理するために使用します。 こちらからダウンロード macの場合はHomeBrewでインストール可能 コマンド: brew install composer php-webdriverのインストール PHPで、seleniumを扱うには、php-webdriverといったライブリをインストールする必要があります。以下のコマンドを実行してください。 curl -sS https://getcomposer.org/installer | php php composer.phar require facebook/webdriver ※または、以下の仕様でも可能です。 composer.jsonを作成 composer.jsonにライブラリ情報を記述 composer install コマンドの実行 composer.jsonの作成 touch composer.json composer.jsonにライブリ情報を記述 { "require":{ "php-webdriver/webdriver":" 1.8.0" } } ライブリのインストール composer install 全体像 sample.php <?php require_once __DIR__ . '/vendor/autoload.php'; use Facebook\WebDriver\Chrome\ChromeOptions; use Facebook\WebDriver\Chrome\ChromeDriver; use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Remote\RemoteWebDriver; use Facebook\WebDriver\WebDriverExpectedCondition; use Facebook\WebDriver\WebDriverBy; $driverPath = realpath('/usr/local/bin/chromedriver'); putenv('webdriver.chrome.driver=' . $driverPath); $driver = ChromeDriver::start(); // Googleへ遷移 $driver->get('https://www.google.co.jp/'); // 5秒待機 $driver->wait(5); // スクリーンショット $file = './sample.png'; $driver->takeScreenshot($file); // ブラウザを閉じる $driver->quit(); ChromeDriverのパス設定 $driverPath = realpath('ChromeDriverのパス'); putenv('webdriver.chrome.driver=' . $driverPath); ※パスを/usr/local/bin/chromedriveとする場合は、権限付与が必要です。 権限を付与するコマンド(/usr/local/bin/chromedrive) mv ~/Downloads/chromedriver /usr/local/bin/ chmod +x /usr/local/bin/chromedriver ChromeDriverの起動 sample.php $driver = ChromeDriver::start(オプション); ページ遷移 sample.php $driver->get('URL'); 待機 sample.php $driver->wait(秒数)->until( // 待機条件 ); スクリーンショット sample.php $driver->takeScreenshot('保存先のパス'); ブラウザを閉じる samaple.php $driver->quit(); まとめ PHPでseleniumを使用する場合は、以下の手順で進めてください。 1. ChromeDriverをインストール 2. Composerのインストール 3. php-webdriverのインストール
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP seleniumを使ってみよう

はじめに PHPで、seleniumを使用したい人 自動化処理に興味がある方 seleniumとは Selenium は、 Webアプリケーションをテストするためのポータブルフレームワークである。 Selenium は、テストスクリプト言語(Selenium IDE)を学ぶ必要なしに、機能テストを作成するための再生ツールを提供する。 出典: フリー百科事典『ウィキペディア(Wikipedia)』 ChromeDriverをインストール ChromeDriverは、Chromeを動かすために必要なドライバーになります。 こちらからダウンロード macの場合はHomeBrewでインストール可能 コマンド: brew install chromedriver selenium-server-standaloneをインストール Windowsはこちらからダウンロード macの場合はHomeBrewでインストール可能 コマンド: brew install selenium-server-standalone Composerのインストール Composerは、PHPのライブラリ管理ツールです。 ※今回は、php-webdriverを使用し管理するために使用します。 こちらからダウンロード macの場合はHomeBrewでインストール可能 コマンド: brew install composer php-webdriverのインストール PHPで、seleniumを扱うには、php-webdriverといったライブリをインストールする必要があります。以下のコマンドを実行してください。 curl -sS https://getcomposer.org/installer | php php composer.phar require facebook/webdriver ※または、以下の仕様でも可能です。 composer.jsonを作成 composer.jsonにライブラリ情報を記述 composer install コマンドの実行 composer.jsonの作成 touch composer.json composer.jsonにライブリ情報を記述 { "require":{ "php-webdriver/webdriver":" 1.8.0" } } ライブリのインストール composer install 全体像 sample.php <?php require_once __DIR__ . '/vendor/autoload.php'; use Facebook\WebDriver\Chrome\ChromeOptions; use Facebook\WebDriver\Chrome\ChromeDriver; use Facebook\WebDriver\Remote\DesiredCapabilities; use Facebook\WebDriver\Remote\RemoteWebDriver; use Facebook\WebDriver\WebDriverExpectedCondition; use Facebook\WebDriver\WebDriverBy; $driverPath = realpath('/usr/local/bin/chromedriver'); putenv('webdriver.chrome.driver=' . $driverPath); $driver = ChromeDriver::start(); // Googleへ遷移 $driver->get('https://www.google.co.jp/'); // 5秒待機 $driver->wait(5); // スクリーンショット $file = './sample.png'; $driver->takeScreenshot($file); // ブラウザを閉じる $driver->quit(); ChromeDriverのパス設定 $driverPath = realpath('ChromeDriverのパス'); putenv('webdriver.chrome.driver=' . $driverPath); ※パスを/usr/local/bin/chromedriveとする場合は、権限付与が必要です。 権限を付与するコマンド(/usr/local/bin/chromedrive) mv ~/Downloads/chromedriver /usr/local/bin/ chmod +x /usr/local/bin/chromedriver ChromeDriverの起動 sample.php $driver = ChromeDriver::start(オプション); ページ遷移 sample.php $driver->get('URL'); 待機 sample.php $driver->wait(秒数)->until( // 待機条件 ); スクリーンショット sample.php $driver->takeScreenshot('保存先のパス'); ブラウザを閉じる samaple.php $driver->quit(); まとめ PHPでseleniumを使用する場合は、以下の手順で進めてください。 1. ChromeDriverをインストール 2. Composerのインストール 3. php-webdriverのインストール
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む