20211007のPHPに関する記事は11件です。

PHPでhello,Worldを表示させる

コード echo "Hello,World"; 結果 Hello,World
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[PHP] 学習メモ

文字の連結 PHPでは'+'ではなく,'.'を連結演算子として使います。 // str型 + str型 echo 'w' . "ord" . PHP_EOL; echo "飛ぶ" . "NO" . PHP_EOL; // 更にPHPでは、int型 . str型 = strになります。 // 連結演算子の場合、PHPはint型とfloat型を勝手にstr型に変更します。 echo "The year is : " . 2000 . PHP_EOL; // float型 . str型 = str型。 echo "Left : " . 20.343 . "km" . PHP_EOL; 文字列のサイズ //文字列のサイズを得るために, strlen()という関数を使います。 strlen(str型) echo strlen("California") . PHP_EOL; // 最後の文字のインデックスは2(=3 - 1) echo "cat"[strlen("cat") - 1] . PHP_EOL; // インデックス演算子を使って、文字列CaliforniaのCをコンソールに出力してください。 echo "California"[strlen("California") - 10] . PHP_EOL; // インデックス演算子を使って、文字列Desktopのkをコンソールに出力してください。 echo "Desktop" [strlen("Desktop") - 4] . PHP_EOL; // 文字列Computerの文字数をstrlen()を使って出力してください。 echo strlen("Computer") . PHP_EOL; // 文字列recursion@info.comの文字数をstrlen()を使って出力してください。 echo strlen("recursion@info.com") . PHP_EOL; // 文字列Computerの最後の文字をstrlen()を使って出力してください。 echo "Computer"[strlen("computer") - 1] . PHP_EOL; // 文字列recursion@info.comの最後の文字をstrlen()を使って出力してください。 echo "recursion@info.com"[strlen("recursion@info.com") - 1] . PHP_EOL; 静的型付け言語 静的型付け言語では変数を宣言する際に、データ型も一緒に割り当てる必要があります。データ型の宣言によって、プログラミング言語がビットを正しく読み取り、データ型を処理することができます。 プログラムを実行する前 (マシンに対して命令が作成される瞬間、つまりコンパイル時) に型検査を行うプログラミング言語を静的型付け言語と呼びます。静的型付け言語の例として、C++、C#、Java などが挙げられます。 動的型付け言語 動的型付け言語の場合、変数を宣言する際に、データ型を割り当てる必要はありません。しかし、動的型付けでは、型を宣言しなくて良いため簡単に実装できる反面、プログラムを実行しないとバグがわからないという難点を持っています。 プログラムの実行時に、型検査を行うプログラミング言語を動的型付け言語と呼びます。動的型付け言語の例として、JavaScript、Python、PHP、Ruby などが挙げられます。 プログラム実行中に型検査が行われる言語を一般に静的型付け言語 プログラム実行前に型検査が行われる言語を一般的に動的型付け言語
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[PHP] 文字列の連結・文字列のサイズ

文字の連結 PHPでは'+'ではなく,'.'を連結演算子として使います。 // str型 + str型 echo 'w' . "ord" . PHP_EOL; echo "飛ぶ" . "NO" . PHP_EOL; // 更にPHPでは、int型 . str型 = strになります。 // 連結演算子の場合、PHPはint型とfloat型を勝手にstr型に変更します。 echo "The year is : " . 2000 . PHP_EOL; // float型 . str型 = str型。 echo "Left : " . 20.343 . "km" . PHP_EOL; 文字列のサイズ //文字列のサイズを得るために, strlen()という関数を使います。 strlen(str型) echo strlen("California") . PHP_EOL; // 最後の文字のインデックスは2(=3 - 1) echo "cat"[strlen("cat") - 1] . PHP_EOL; // インデックス演算子を使って、文字列CaliforniaのCをコンソールに出力してください。 echo "California"[strlen("California") - 10] . PHP_EOL; // インデックス演算子を使って、文字列Desktopのkをコンソールに出力してください。 echo "Desktop" [strlen("Desktop") - 4] . PHP_EOL; // 文字列Computerの文字数をstrlen()を使って出力してください。 echo strlen("Computer") . PHP_EOL; // 文字列recursion@info.comの文字数をstrlen()を使って出力してください。 echo strlen("recursion@info.com") . PHP_EOL; // 文字列Computerの最後の文字をstrlen()を使って出力してください。 echo "Computer"[strlen("computer") - 1] . PHP_EOL; // 文字列recursion@info.comの最後の文字をstrlen()を使って出力してください。 echo "recursion@info.com"[strlen("recursion@info.com") - 1] . PHP_EOL; 静的型付け言語 静的型付け言語では変数を宣言する際に、データ型も一緒に割り当てる必要があります。データ型の宣言によって、プログラミング言語がビットを正しく読み取り、データ型を処理することができます。 プログラムを実行する前 (マシンに対して命令が作成される瞬間、つまりコンパイル時) に型検査を行うプログラミング言語を静的型付け言語と呼びます。静的型付け言語の例として、C++、C#、Java などが挙げられます。 動的型付け言語 動的型付け言語の場合、変数を宣言する際に、データ型を割り当てる必要はありません。しかし、動的型付けでは、型を宣言しなくて良いため簡単に実装できる反面、プログラムを実行しないとバグがわからないという難点を持っています。 プログラムの実行時に、型検査を行うプログラミング言語を動的型付け言語と呼びます。動的型付け言語の例として、JavaScript、Python、PHP、Ruby などが挙げられます。 プログラム実行中に型検査が行われる言語を一般に静的型付け言語 プログラム実行前に型検査が行われる言語を一般的に動的型付け言語
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Raspberry Pi 3+の設定(忘備録)その4 MySQL(mariaDB)インストール

今までRaspberry Pi 3+に16GBのmicroSDを挿してwebサーバとして運用していましたが、手狭になってきたので64GBに改めて環境構築をした時の自分の作業の忘備録です。以前導入した時とだいぶ変わっている部分が多かったので驚いたのが第一印象でした。 前提 このラズベリーパイは外部に公開はしません。(twitterへのポストはします) 普段、このRaspberry Pi 3+は午前7時から午後11時まで30分毎にcronでbotを運用しています。 そのため一日当たりの作業時間は夜間の23時から0時までの1時間ぐらいをメンテナンス時間として作業を行う予定です。 またこういう世界から遠ざかって久しいのでいろいろと拙い部分があると思います。ご指摘ください。 関連ページ https://qiita.com/cafe-capitola/items/b5e3e5dfdc8ca9f9a744 https://qiita.com/cafe-capitola/items/283f41793cde409a36a6 https://qiita.com/cafe-capitola/items/d167b4e96fa78dc8878c https://qiita.com/cafe-capitola/items/97dd713185049d4a8274 https://qiita.com/cafe-capitola/items/9f97c791a598420a7e57 MySQL(MariaDB)インストール 今回、今までと同じようにphpmyadminを入れようと思ったのですが、インストールしてもユーザー周りがうまくいかずに困ったので、運用はとりあえず全部SQLコマンドを叩いて実行することにしようと思います。 参考にしたサイトはこちら。 https://naokeyzmt.com/rogue/skillup-raspberrypi-lamp/ MySQLを入れようとすると、なんだか「無い」と怒られるのでmariaDBをインストールしました。 $ sudo apt install mariadb-server mariadbインストール後、設定を行っていきたいと思います。 次にこちら。 $ sudo /usr/bin/mysql_secure_installation $ sudo systemctl start mariadb.service 設定することは以下の点 rootのパスワード設定 → 設定する 匿名ユーザーの有無 → いらない リモートログインの有無 → 今回はコマンドラインで実行するので使うかもしれない testデータベースの有無 → いらない 設定の反映 → やる ここまでやって、ログインできるか確認します。まずは何もオプションなし。 $sudo mysql Welcome to the MariaDB monitor. Commands end with ; or \g. Your MariaDB connection id is 36 Server version: 10.3.29-MariaDB-0+deb10u1 Raspbian 10 Copyright (c) 2000, 2018, Oracle, MariaDB Corporation Ab and others. 何もなしで入れると思います。それではユーザーを手動で作成していこうと思います。 # ユーザー追加 create user `任意のユーザー名`@`localhost` IDENTIFIED BY '任意のパスワード'; # 追加したユーザーに権限を付加。mysql8以降では書式が変わったそうです。 GRANT ALL PRIVILEGES ON *.* TO `任意のユーザー名`@'localhost' WITH GRANT OPTION; # 反映 FLUSH PRIVILEGES; ここまでやって、追加したユーザーが見えるか確認したいと思います。 MariaDB [(none)]> SELECT Host, User, Password FROM mysql.user; +-----------+-------------+-------------------------------------------+ | Host | User | Password | +-----------+-------------+-------------------------------------------+ | localhost | root | *xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx| | localhost | hoge-hoge | *yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy| +-----------+-------------+-------------------------------------------+ パスワードには暗号化された値が入っています。 次に、先ほど指定したユーザーでログインできるか確認してみたいと思います。 $ sudo mysql --host=localhost --user=hoge-hoge --password=xxxxxxxxxxxxxxxxxxxxxx こっちでも行けます。 $ sudo mysql -uhoge-hoge -p Enter password: ここまで行ければ、あとはコマンドラインで何とかなると思います。と、思いましたが…。 PDOでMySQLにつながらない(解決済み) まずは、PDOのドライバーが必要なのでインストール $ sudo apt-get -y install php-mysql さらにphp.iniのmysqlやpdoと書いてある行のコメントアウトをかたっぱしから外していきます。 phpinfoにも PDO drivers mysql の記載があることを確認。 https://kahoo.blog/php-pdo-check-mysql-connection-code/ こちらのソースコードを参考にrootによる接続確認をしてみる。 <?php // defineの値は環境によって変えてください。 define('HOSTNAME', 'localhost'); define('DATABASE', 'hoge_data'); define('USERNAME', 'root'); define('PASSWORD', 'root-hoge'); try { /// DB接続を試みる $db = new PDO('mysql:host=' . HOSTNAME . ';dbname=' . DATABASE, USERNAME, PASSWORD); $msg = "MySQL への接続確認が取れました。"; } catch (PDOException $e) { $isConnect = false; $msg = "MySQL への接続に失敗しました。<br>(" . $e->getMessage() . ")"; } ?> <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8" /> <title>MySQL接続確認</title> </head> <body> <h1>MySQL接続確認</h1> <p><?php echo $msg; ?></p> </body> </html> MySQL接続確認 MySQL への接続に失敗しました。 (SQLSTATE[HY000] [1698] Access denied for user 'root'@'localhost') rootでつながりません。 MySQL5.7ではsudo権限でないとrootに接続出来ないとの事。上記で作成した別アカウントで再度接続を試みます。 ...つながりました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Raspberry Pi 3+の設定(忘備録)その3 新規ユーザー作成・PHPのインストール

今までRaspberry Pi 3+に16GBのmicroSDを挿してwebサーバとして運用していましたが、手狭になってきたので64GBに改めて環境構築をした時の自分の作業の忘備録です。以前導入した時とだいぶ変わっている部分が多かったので驚いたのが第一印象でした。 前提 このラズベリーパイは外部に公開はしません。(twitterへのポストはします) 普段、このRaspberry Pi 3+は午前7時から午後11時まで30分毎にcronでbotを運用しています。 そのため一日当たりの作業時間は夜間の23時から0時までの1時間ぐらいをメンテナンス時間として作業を行う予定です。 またこういう世界から遠ざかって久しいのでいろいろと拙い部分があると思います。ご指摘ください。 関連ページ https://qiita.com/cafe-capitola/items/b5e3e5dfdc8ca9f9a744 https://qiita.com/cafe-capitola/items/283f41793cde409a36a6 https://qiita.com/cafe-capitola/items/d167b4e96fa78dc8878c https://qiita.com/cafe-capitola/items/97dd713185049d4a8274 https://qiita.com/cafe-capitola/items/9f97c791a598420a7e57 新しいユーザーを作成する ずっとデフォルトユーザーのpiを使用していると、セキュリティ上物騒である為、新しくユーザーを作成します。 新しいユーザーを作成する際は、sudoが使用できるグループに所属させます。(私はこれでsudoが使用できないユーザーを作成した後にpiを凍結させて、$ sudo su - することもできずに環境を一度imgファイルから書き戻す羽目になりました。) 新しいユーザー作成後、piは削除するかアカウント凍結を行いましょう。 #グループの作成 $ sudo groupadd -(グループ番号) (グループ名)  #ユーザーの作成 $ sudo useradd -m (ユーザー名) #ユーザーのパスワードの設定 $ sudo passwd (ユーザー名) #ユーザーが所属するグループの追加。 $ sudo usermod (グループ名、カンマ区切りで複数指定可) (ユーザー名) $ groups (ユーザー名) #↑実行すると、そのユーザーが所属しているグループ名一覧が表示される。 #新しいユーザー名を作成する時はpiのグループをそれで取得してusermodで追加することも可能。 phpのインストール 以下のコマンドを実行し、phpとphp-curlをインストールします。(php-curlがないとtwitteroAuthが動きません) $ sudo apt-get update $ sudo apt-get upgrade $ sudo apt-get install php $ sudo apt-get install php-curl マルチバイト文字を使用するため、mbstring.dllのコメントアウトを外します。 php.ini ;(略) ;;;;;;;;;;;;;;;;;;;;;; ; Dynamic Extensions ; ;;;;;;;;;;;;;;;;;;;;;; ;(略 ↓行頭のセミコロンを削除し、このコメントアウトを外す) extension=mbstring ; さらに足りないのでモジュールを追加します。 $ sudo apt-get install php-mbstring とりあえずのセキュリティ設定 自分はセキュリティの専門家ではないので、一番世間で騒がれているセキュリティを一通り行うこととします。 DirecrotryIndex系は自分の環境ではwwwが置かれているディレクトリは別ディレクトリに複数分かれているため行いません。都度.htaccessに記載することにします。 もし過不足、誤りなどございましたらご指摘ください。 参考サイトはこちら https://qiita.com/bezeklik/items/1c4145652661cf5b2271 /etc/php/x.y/apache2php.ini #ファイルパスx.yはPHPのバージョン。 #エラー非表示 display_errors=off #エラーログ出力設定 log_errors=on #バージョン非表示 expose_php=off httpリクエストのヘッダの追加・削除・変更を行います。これを行わないとサービス再起動時に後述のheaderなんちゃら系のエラーが出力されます。 $ sudo a2enmod headers /etc/apache2/conf-available/security.conf #バージョン非表示 ServerTokens Prod ServerSignature off Header unset "X-Powered-By" #httpoxy対策 RequestHeader unset Proxy #クリックジャッキング対策 Header append X-Frame-Options SAMEORIGIN #XSS対策 Header set X-XSS-Protection "1; mode=block" Header set X-Content-Type-Options nosniff #XST対策 TraceEnable Off サービスを再起動します。 $ sudo /etc/init.d/apache2 restart サービス再起動時にエラーが出力されない事を確認してください。 念のためこのあたりでWin32DiskImagerでmicroSDのイメージをコピーしておくことをお勧めします。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

画像のアップロード 参考サイト

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel8 コントローラの使い方

Laravelにおけるコントローラクラスを理解しよう 人気のPHPフレームワークLaravelを習得しよう 第4回 https://codezine.jp/article/detail/11524 こちらで勉強しててLaravel8ではハマったのでメモします。 おそらく記事はver8以前の記述ではないかと思います。 1.実装内容(エラー版) ページに記載通りに ①Control Class \app\Http\Controllers\HelloBladeWithDataController.php <?php namespace App\Http\Controllers; // (1) use App\Http\Controllers\Controller; // (2) class HelloBladeWithDataController extends Controller // (3) { public function __invoke() // (4) { $data["name"] = "武者小路"; // (5) return view("helloWithData", $data); // (5) } } ②web.php web.php Route::get("/chap4/helloBladeWithData", "HelloBladeWithDataController"); ③View Class \resources\views\helloWithData.blade.php <?php namespace App\Http\Controllers; // (1) use App\Http\Controllers\Controller; // (2) class HelloBladeWithDataController extends Controller // (3) { public function __invoke() // (4) { $data["name"] = "武者小路"; // (5) return view("helloWithData", $data); // (5) } } 2.エラー内容 ◆メッセージ UnexpectedValueException Invalid route action: [HelloBladeWithDataController]. ◆イメージ 3.原因 Larave8でWeb.phpの記載ルールが変わった模様。。 4.対処法 web.php // エラー例 //Route::get("/chap4/helloBladeWithData", "HelloBladeWithDataController"); // 正解 Route::get("/chap4/helloBladeWithData", \App\Http\Controllers\HelloBladeWithDataController::class); 5.おまけ invoke使わない例 url control class control method /chap4/helloMusha \App\Http\Controllers\Chap4Controller helloMusha /chap4/helloNakano 同上 helloNakano \app\Http\Controllers\Chap4Controller.php <?php namespace App\Http\Controllers; use App\Http\Controllers\Controller; class Chap4Controller extends Controller { public function helloMusha() // (1) { $data["name"] = "武者小路"; // (2) return view("helloWithData", $data); // (2) } public function helloNakano() // (3) { $data["name"] = "中野"; // (4) return view("chap3.hello", $data); // (4) } } web.php Route::get("/chap4/helloMusha", [\App\Http\Controllers\Chap4Controller::class,'helloMusha']); Route::get("/chap4/helloNakano", [\App\Http\Controllers\Chap4Controller::class,'helloNakano']); 参考元
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel での ajax を利用したファイルアップロード

はじめに Laravelを使っている案件でファイルアップロードを行う機会があったので、実装方法を記します。 なぜajaxを利用したかというと、編集画面というフォームの中でファイルアップロード機能を実装したかったから(編集画面で画面遷移することなくファイルアップロードのみ行いたかったから) HTML <div> <label for="" class="">ファイルのアップロード</label> <div class=""> <input type="file" class="" id="upload_file" name="upload_file" accept="pdf, xlsx" style=''> </div> <input type="button" value="アップロード" id="upload" data-toggle="modal" data-target="#file_upload_modal" class="" style=''> </div> @component('includes.popup_modal', ['id' => 'file_upload_modal']) @slot('title') ファイルのアップロード @endslot @slot('body') ファイルのアップロード <label style="" class="" id="searchErrorMessage"></label> @endslot @slot('footer') <button type="button" id="file_upload_btn" class="">アップロード</button> <button type="button" class="" data-dismiss="modal">キャンセル</button> @endslot @endcomponent アップロードボタンをクリックするとモーダルを表示して「アップロード」ボタンを選択する事でアップロード処理を行います。 モーダルは別ファイルで管理しています。 ajax <script> $(document).ready(function () { $('#file_upload_btn').on('click', function() { //ajaxでのcsrfトークン送信 $.ajaxSetup({ headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } }); //アップロードするファイルのデータ取得 var fileData = document.getElementById("upload_file").files[0]; //フォームデータを作成する var form = new FormData(); //フォームデータにアップロードファイルの情報追加 form.append("file", fileData); $.ajax({ type: "POST", url: "{{ route('ajax_file_upload', ['id' => $id']) }}", data: form, processData: false, contentType: false, success: function (response) { if(response.is_success) { //モーダルの処理 //エラーメッセージ非表示 $('#searchErrorMessage').html(''); $('#searchErrorMessage').hide(); //モーダルを閉じる $('#file_upload_modal').modal('toggle'); } else { //モーダルでのエラーメッセージ表示処理 var msg = ""; $.each(response.errors_message, function (i, v) { msg += v + "<br>"; }); $('#searchErrorMessage').html(msg); $('#searchErrorMessage').show(); } }, error: function (response) { //エラー時の処理 } }); }) }) </script> headers: { 'X-CSRF-TOKEN': $('meta[name="csrf-token"]').attr('content') } ここでCSRF保護のためcsrf-tokenをヘッダーに設定します。 これを行わないとエラーになります。 あとは var form = new FormData(); フォームデータを作成してあげてこれを指定のControllerに渡します。 ここでは url: "{{ route('ajax_file_upload', ['id' => $id']) }}", ajax_file_upload というrouteに渡してます PHP(LaravelのController) Controllerでファイル情報を受け取ってサーバに保存します。 public function uploadFile(Request $request, $id){ $response = []; //元ファイルのファイル名取得 $fileName = $request->file('file')->getClientOriginalName(); //拡張子チェック $ext = pathinfo($fileName)['extension']; $check_extension = ['xlsx', 'pdf']; if(!in_array($ext, $check_extension, true)){ $response = [ 'is_success' => false, 'errors_message' => ["エクセルファイルかPDFファイルのみアップロード可能です"] ]; return response()->json($response); } //ファイル保存 $upload_file_save = config('upload'); $request->file('file')->storeAs($upload_file_save . $id, $fileName); $response = [ 'is_success' => true, 'errors_message' => [""] ]; return response()->json($response); } $fileName = $request->file('file')->getClientOriginalName(); getClientOriginalName で元のファイル名を取得できます。 ※元ファイル名を利用しなかった場合はPHPが任意に決めたファイル名になります。 $response = [ 'is_success' => false, 'errors_message' => ["エクセルファイルかPDFファイルのみアップロード可能です"] ]; エラーが起こった際に(この際は拡張子チェックでエラー)アップロードする際に確認を行ったモーダルにエラーメッセージを返します。 $upload_file_save = 'upload' . $id; $request->file('file')->storeAs($upload_file_save, $fileName); storeAs でファイル名の指定が可能です。ここではアップロードした元のファイル名。 また、アップロード先のディレクトリは指定しなければ storage/app となります ここでは storage/app/upload/{$id} となります。 さいごに これで最低限の実装は出来る、はず、です 間違いなどありましたらご指摘ください。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel構成

はじめに laravelにふれる機会が増えてきたため、ディレクトリ構成をメモしておきます。 laravelのディレクトリ構成 ─── Laravel ├── app ・・・アプリケーションのロジック ├── bootstrap ・・・laravelフレームワークの起動コード ├── config ・・・設定ファイル ├── database ・・・MigrationファイルなどDB関連 ├── public ・・・Webサーバのドキュメントルート ├── resources ・・・ビューや言語変換用ファイルなど ├── routes ・・・ルーティング用ファイル ├── storage ・・・フレームワークが使用するファイル ├── tests ・・・テストコード └── vendor ・・・Composerでインストールしたライブラリ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【第六回】コロナ禍だから何かできることをー 自宅療養者連絡ツール ー

前回までのあらすじ 【第五回】コロナ禍だから何かできることを 実装イメージ図 LINEを利用して保健所の担当者の負担を軽減するとともに、自宅療養者はいつでもつながっている安心感を持たせるためのツールイメージです。 ユーザー登録の仕組みを作ろう 今回はLIFFで表示する画面の開発部分です 初期表示の処理 1.LINE IDを渡して、データベースに存在するかチェックをする。 2.存在した場合は、「すでに登録されています」と表示。 3.存在しない場合は、「連絡を受けたユーザーIDを入力してください。」として、登録フォームを表示する。 ユーザー登録の処理 1.入力項目のチェックを行う。 2.エラーがなければ、LINE IDと入力されたユーザーIDをデータベースへ登録する。 3.「登録しました」と返す。 4.LIFFの画面を閉じる。 登録画面 登録済画面 参考資料 LIFFアプリを開発する LIFFアプリを開く 以下、ソースコードはこちら index.php <?php header( 'Expires: Thu, 01 Jan 1970 00:00:00 GMT' ); header( 'Last-Modified: '.gmdate( 'D, d M Y H:i:s' ).' GMT' ); ?> <!DOCTYPE html> <html lang="ja"> <head> <meta http-equiv="Pragma" content="no-cache"> <meta http-equiv="Cache-Control" content="no-cache"> <title>ユーザー登録</title> <style> *{ margin: 0; padding: 0; -webkit-box-sizing: border-box; box-sizing: border-box; -webkit-user-select: none; -moz-user-select: none; -ms-user-select: none; user-select: none; font-size:120%; } :focus { outline: none; } a{ text-decoration: none; } #container{ width:80%; margin:0 auto; } #title{ position:fixed; height:10%; left:0; right:0; top:0; text-align:center; } #user_id{ position:fixed; height:10%; width:80%; left:10%; right:10%; top:20%; } #message{ position:fixed; bottom:20%; left:10%; right:10%; width:80%; top:40%; height:30%; color:#f00; } #submit{ position: fixed; bottom: 10%; height:10%; width:80%; left:10%; right:10%; } #loading{ position: fixed; height:100%; width:100%; top:0; bottom: 0%; left:0%; right:0%; z-index:999; background-color:#fff; text-align:center; display: flex; justify-content: center; align-items: center; } </style> <!-- jQuery読み込み --> <script src="https://ajax.googleapis.com/ajax/libs/jquery/3.6.0/jquery.min.js"></script> <script charset="utf-8" src="https://static.line-scdn.net/liff/edge/2.1/sdk.js"></script> <script> $(function() { // LIFFの初期化を行う $('#log').append('START<br>'); liff.init({ liffId: "自分のLIFF ID(URLから『https://liff.line.me/』を除いた文字列)を入力する" }).then(() => { // 初期化完了. 以降はLIFF SDKの各種メソッドを利用できる $('#log').append('GET<br>'); // 利用者のLINEアカウントのプロフィール名を取得 liff.getProfile().then(function(profile) { // ユーザーID const line_id = profile.userId; // プロフィール名 const name = profile.displayName; // HTMLに挿入 $("#line_id").val(line_id); $('#log').append('liff.getProfile()=' + JSON.stringify(profile) + '<br>'); get_profile(line_id); $('#log').append('END<br>'); }).catch(function(error) { $('#log').append('ERROR<br>'); }); }) function get_profile(line_id){ $('#log').append('get_profile START<br>'); try { $.ajax({ type : 'POST' ,url : 'ajax_line.php' ,dataType : 'json' ,data : { mode : 'get' ,line_id : line_id } ,cache : false }).done(function(data, textStatus, jqXHR){ //エラーメッセージが存在しない場合は再描画 if(data['error']==""){ if(data['status']=="NA"){ $("#loading").hide(); }else{ $("#load_error").text("すでに登録されています"); setTimeout(function(){ liff.closeWindow(); },2000); } }else{ $("#load_error").text(data['error']); } }).fail(function(XMLHttpRequest, textStatus, errorThrown){ $('#log').append('ERROR<br>'); $("#load_error").text("データを取得できません"); }); }catch(e){ $('#log').append('ERROR<br>'); $("#load_error").text(e.message); } $('#log').append('get_profile END<br>'); } function set_profile(){ var user_id = $("#user_id").val(); var line_id = $("#line_id").val(); $('#log').append('set_profile START<br>'); try { $.ajax({ type : 'POST' ,url : 'ajax_line.php' ,dataType : 'json' ,data : { mode : 'set' ,user_id : user_id ,line_id : line_id } ,cache : false }).done(function(data, textStatus, jqXHR){ //エラーメッセージが存在しない場合は再描画 if(data['error']==""){ $("#message").text("登録しました"); setTimeout(function(){ liff.closeWindow(); },2000); }else{ $("#message").text(data['error']); } }).fail(function(XMLHttpRequest, textStatus, errorThrown){ $("#message").text("データを取得できません"); }); }catch(e){ $("#message").text(e.message); } $('#log').append('set_profile END<br>'); } //登録ボタン押下処理 $("body").on({ "click" : function(){ set_profile(); } }, "#submit") }); </script> </head> <body> <div id="container"> <h1 id="title">連絡を受けたユーザーIDを入力してください。</h1> <input type="text" id="user_id"> <input type="hidden" id="line_id"> <input type="button" id="submit" value="登録"> </div> <div id="message"></div> <div id="log" style="display:none;width:96%;height:100px;"></div> <div id="loading"><p id="load_error">now loading...</p></div> </body> </html> <!-- liff.closeWindow() --> ajax_line.php <?php require_once("./config.php"); //JSからのデータを受け取る $mode = filter_input(INPUT_POST, 'mode'); // $_POST['mode']とも書ける $line_id = filter_input(INPUT_POST, 'line_id'); // $_POST['line_id']とも書ける $user_id = filter_input(INPUT_POST, 'user_id'); // $_POST['user_id']とも書ける $error_message = ""; //DB接続 if($error_message == ""){ try{ $dbh = new PDO(DATABASE_URL, DATABASE_USER, DATABASE_PASS); // 静的プレースホルダを指定 $dbh->setAttribute(PDO::ATTR_EMULATE_PREPARES, false); // エラー発生時に例外を投げる $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION); }catch(PDOException $ex){ $error_message = "接続エラー"; } } //ユーザー情報取得 if($error_message == ""){ try{ $SQL = <<<EOM SELECT USER_ID, USER_NAME FROM LINE_USER WHERE LINE_ID = ? EOM; $stmt = $dbh->prepare($SQL, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL)); $stmt->bindParam(1, $line_id, PDO::PARAM_STR); $stmt->execute(); }catch(PDOException $ex){ $error_message = "ユーザー情報取得エラー"; } } //データ取得 if($error_message == ""){ if($stmt->rowCount() > 0){ $row = $stmt->fetch(PDO::FETCH_NUM, PDO::FETCH_ORI_NEXT); $user_id = $row[0]; $user_name = $row[1]; } } // 更新処理の時はユーザーIDがあるかチェックする if($error_message == "" && $mode == "set"){ if ($user_id==""){ $error_message = "ユーザーIDが入力されていません"; }else{ try{ $SQL = <<<EOM SELECT USER_ID, USER_NAME FROM LINE_USER WHERE USER_ID = ? EOM; $stmt = $dbh->prepare($SQL, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL)); $stmt->bindParam(1, $user_id, PDO::PARAM_STR); $stmt->execute(); }catch(PDOException $ex){ $error_message = "ユーザー情報取得エラー"; } //データ取得 if($error_message == ""){ if($stmt->rowCount()==0){ $error_message = "ユーザーIDが登録されていません"; } } } } //アクション if($error_message == ""){ if($mode == "get"){ if ($user_id==""){ $status = "NA"; } }elseif($mode == "set"){ //トランザクション処理を開始 $dbh->beginTransaction(); try { $SQL = <<<EOM UPDATE LINE_USER SET LAST_ACCESS = NOW() ,LINE_ID = :line_id WHERE USER_ID = :user_id EOM; $stmt = $dbh->prepare($SQL, array(PDO::ATTR_CURSOR => PDO::CURSOR_SCROLL)); $stmt->bindParam(':user_id', $user_id, PDO::PARAM_STR); $stmt->bindParam(':line_id', $line_id, PDO::PARAM_STR); $stmt->execute(); //コミット $dbh->commit(); }catch(Exception $ex){ //ロールバック $dbh->rollback(); $error_message = "登録に失敗しました"; } }else{ $error_message = "予期しないエラーが発生しました"; } } $list = array( "error" => $error_message, "status" => $status ); //JSONデータを出力 header("Content-Type: application/json; charset=UTF-8"); //ヘッダー情報の明記。必須。 echo json_encode($list); exit; //処理の終了 ?> config.php <?php define("DATABASE_URL", 'mysql:host=アドレス;dbname=データベース名;charset=utf8'); define("DATABASE_USER", '接続ユーザー名'); define("DATABASE_PASS", '接続パスワード'); ?> コロナ禍だから何かできることをー 自宅療養者連絡ツール ー 【第一回】実装イメージ図と動画 【第二回】LINEからデータを取得して返すまでの流れ 【第三回】LINEからデータベースまでの流れ 【第四回】データベースへの更新までの流れ 【第五回】ユーザー登録の仕組み-LINEbotの設定部分 ->>【第六回】ユーザー登録の仕組みLIFFで表示する画面の開発 【第七回】データベースの構造 【第八回】WEB画面上でできる機能 【第九回】まとめ
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

php Slim3からSlim4へ移行する際のメモ

以下の手順を参考に作業。 https://codezine.jp/article/detail/11904 ライブラリのバージョンアップ + 追加インストール //update composer require slim/slim composer require monolog/monolog //追加 composer require slim/psr7 composer require php-di/php-di 移行作業 index.phpの修正 DIコンテナの変更のため、index.phpとdependencies.phpの設定を変更。 Slim\Factory\AppFactoryとDI\Containerを使うように変更。 use Slim\Factory\AppFactory; use DI\Container; 以下の流れ settingのjsonを取得。 containerを作成。 containerにsettingをsetしてdependenciesにcontainerを渡してまたcontanierを返してもらう そのcontainerを素にAppFactoryでcreateする。 // Instantiate the app $settings = require __DIR__ . '/../src/settings.php'; // Set up dependencies $container = new Container(); $container->set('settings', $settings['settings']); $dependencies = require __DIR__ . '/../src/dependencies.php'; $container = $dependencies($container); AppFactory::setContainer($container); $app = AppFactory::create(); dependencies.phpはcontainerを受け取るように修正して、 contaier->setで保存するようにする。 use DI\Container; return function (Container $container) { $container->set('renderer', function ($c) { ...省略 App/HTTP/系をSlim\Psr7\系に変更 // use Slim\Http\Request; // use Slim\Http\Response; use Slim\Psr7\Request; use Slim\Psr7\Response; middlewareを変更 クロージャーで作成していたmiddlewareにうまく引数がわたせなくなったので、classで作成するように修正。 $requireLogin = function ($request, $response, $next) { // } //上記処理を $app->get('/user/index', UserController::class . ':index')->add($requireLogin); ↓以下の感じに直す //classを1ファイルで作成 <?php class RequireLoginMiddleware { public function __construct($db) { // } public function __invoke(Request $request, RequestHandler $handler): Response { //処理 } } //インスタンスをaddする //引数を渡すときはコンストラクタに渡して保持してもらう。 $app->get('/user/index', UserController::class . ':index')->add(new RequireLoginMiddleware()); エラー1 Uncaught TypeError: Slim\Handlers\Strategies\RequestResponse::__invoke(): Return value must be of type Psr\Http\Message\ResponseInterface, null controllerの中でresponseを明確にreturnしないと上記エラーがでるようになった。middlewareの影響かも。各所にreturn $response;を追加。 エラーハンドリングの修正 dependencies.phpで設定していたエラーハンドラはCustomErrorHandlerとして別ファイルに外だし。 index.phpの中で設定を追加。 参考https://codezine.jp/article/detail/12397?p=3 class CustomErrorRenderer implements ErrorRendererInterface { private $container; public function __construct(ContainerInterface $container) { $this->container = $container; } public function __invoke(Throwable $exception, bool $displayErrorDetails): string { $msg =[]; if($exception instanceof HttpNotFoundException) { $msg = ['message' => 'Not Found']; }elseif($exception instanceof HttpMethodNotAllowedException) { $msg = ['message' => 'Method Not Allowed']; }else{ $msg =['message' => 'Internal Server Error']; } return json_encode($msg); } } # index.php $app = AppFactory::create(); // 以下追加 $app->addRoutingMiddleware(); $errorMiddleware = $app->addErrorMiddleware(true, true, true); $errorHandler = $errorMiddleware->getDefaultErrorHandler(); $errorHandler->forceContentType('application/json'); $errorHandler->registerErrorRenderer('application/json', CustomErrorRenderer::class); UnitTestの修正 settingやcontainer周りはindex.phpと同じように修正。 responseの取得をprocessからhandleに変更 $response = $app->process($request, $response); ↓ $response = $app->handle($request); -Request::createFromEnvironment($environment);が使えなくなったので、自前でcreateRequst()を追加。 参考 https://github.com/slimphp/Slim-Skeleton/blob/master/tests/TestCase.php#L68 https://discourse.slimframework.com/t/migrating-from-slim-3-to-4-writing-php-unit-tests/4193/2 合わせてgetのquery parameterの渡し方の変更が必要になった。URLに?+クエリーをそのままつけていたが、?がついているとエスケープされて404になってしまう。以下のように修正。 $request =$request->withQueryParams(['key'=> 'value']);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む