20210412のPHPに関する記事は17件です。

phpフレームワークの仕組み/ネームスペース

こちらの講座でフレームワークの中身学習中です。 https://www.udemy.com/course/php-mvc-from-scratch ポイントポイントで学んだことを書いていこうと思います! 今回はネームスペースと、あえてそれを使わない方法について。 ネームスペース/名前空間とは? phpファイルでclassを利用する時に、複数のファイルに分けてclassの情報を(整頓のため)書いているとします。 例えば別ファイル「post.php」に「Postクラス」の情報があるとします。 その情報を別のファイルで使うには require post.php で読み込まなきゃいけません。 で、こういう別ファイル、別classががたくさん存在している時に、自分がどのクラスを使ってるかをわかりやすくするために使うものが名前空間です。 ※名前衝突を避けるために使われます。 namespace App; class Product{ //例えばこの場合、このクラスを利用して新しくProductオブジェクトを作ると、 //App\Product classのオブジェクトが作られます。 } namespace App\Core; class Product{ //こちらの場合、このクラスを利用して新しくProductオブジェクトを作ると、 //App\Core\Product classのオブジェクトが作られます。 } 名前空間をあえて使いたくない時 例えば、日付に関する情報を取得したいとき。 グローバルクラスの DateTimeを使うとします。 namespace App; //classの記述は省略 $date = new DateTime(); //→Appの中のDateTime classがないとフェータルエラー! このようにnewでDateTime()オブジェクトを作ると、Appの中のDataTme()を使ってしまいます。 namespace Appの宣言をしているからですね。 つまり、App\DataTme のclassがなければエラーになります。 もしそんなclassを作ってたとしても、この状態だと これ https://www.php.net/manual/ja/class.datetime.php を使いたいのか、 または自作の App\DataTme を本当に使いたいのかが他の人からはわかりません。 この場合は $datatime = new \DateTme(); とかきます。 バックスラッシュが入ることで、ネームスペースは使わないぞ!と明示的に宣言することができます。 こちらも参考にいたしました! https://www.php.net/manual/ja/language.namespaces.faq.php#language.namespaces.faq.shouldicare
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

webプログラミングで作る最初の題材は掲示板だよね、本気で作った結果

最終的にはレンタル掲示板になるよね 無料レンタル掲示板NIERU.NET http://nieru.net 掲示板サンプル http://nieru.net/sample/ PHP7.4 mysql 自分が利用してたサービスだからこそ作れるよね 携帯専用掲示板サイトを5年以上利用してそのサイトを10年以上運営して 掲示板サイト利用者からレンタル掲示板運営者になれて1つの夢が叶った感じ 最初は挫折するよね 2013年頃、PHPの勉強がてら掲示板を作ろうと努力したけど検索機能を実装する辺りで挫折した 当時は何がダメなのかも分からなかった フレームワークは便利らしいよね コードの書き方は全て自分ルールになっている 共同開発しないから問題はなし 何処かの会社で働くこともしないから問題なし 仕事を受注しないから問題なし ソースコードは見せられないよね if,swtich,includeのオンパレード 自分がわかれば問題ない 機能は沢山付けるよね いろんなレンタル掲示板サイトを参考にして取り込める機能は全て取り込んだ 一部の有料レンタル掲示板より機能が豊富になった バグはたくさん出るけど気付かないよね レンタル掲示板を開始して利用者が増えたおかげで見つかるバグがある バグを報告してくれる方もいるので、利用ユーザーと一緒に作り上げてる感が良いよね
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel Sail 使って開発したかっただけなのに......

はじめに laravel でコンテナ開発を一瞬で始められると噂のLaravel Sail 使って意気揚々と開発始めたらハマった。。。 ちなみに下記記事参考にしました。 やりたかったこと ただ Laravel 使ってdocker環境で開発したかっただけなのに。。。 まずは4コマンドでLaravelアプリ作成 terminal $ curl -s https://laravel.build/larademo | bash $ cd larademo $ ./vendor/bin/sail up -d $ ./vendor/bin/sail php artisan vendor:publish --tag=serverless-config docker-compose.yml docker-compose.yml version: '3' services: laraveldemo: # コンテナ名は変更した。元々はlaravel.test build: context: ./vendor/laravel/sail/runtimes/8.0 dockerfile: Dockerfile args: WWWGROUP: '${WWWGROUP}' image: sail-8.0/app ports: - '${APP_PORT:-80}:80' environment: WWWUSER: '${WWWUSER}' LARAVEL_SAIL: 1 volumes: - '.:/var/www/html' networks: - sail depends_on: - mysql # - pgsql # - redis # - selenium # selenium: # image: 'selenium/standalone-chrome' # volumes: # - '/dev/shm:/dev/shm' # networks: # - sail mysql: image: 'mysql:8.0' ports: - '${FORWARD_DB_PORT:-3306}:3306' environment: MYSQL_ROOT_PASSWORD: '${DB_PASSWORD}' MYSQL_DATABASE: '${DB_DATABASE}' MYSQL_USER: '${DB_USERNAME}' MYSQL_PASSWORD: '${DB_PASSWORD}' MYSQL_ALLOW_EMPTY_PASSWORD: 'yes' volumes: - 'sailmysql:/var/lib/mysql' networks: - sail healthcheck: test: ["CMD", "mysqladmin", "ping"] # pgsql: # image: postgres:13 # ports: # - '${FORWARD_DB_PORT:-5432}:5432' # environment: # PGPASSWORD: '${DB_PASSWORD:-secret}' # POSTGRES_DB: '${DB_DATABASE}' # POSTGRES_USER: '${DB_USERNAME}' # POSTGRES_PASSWORD: '${DB_PASSWORD:-secret}' # volumes: # - 'sailpostgresql:/var/lib/postgresql/data' # networks: # - sail # healthcheck: # test: ["CMD", "pg_isready", "-q", "-d", "${DB_DATABASE}", "-U", "${DB_USERNAME}"] # redis: # image: 'redis:alpine' # ports: # - '${FORWARD_REDIS_PORT:-6379}:6379' # volumes: # - 'sailredis:/data' # networks: # - sail # healthcheck: # test: ["CMD", "redis-cli", "ping"] # memcached: # image: 'memcached:alpine' # ports: # - '11211:11211' # networks: # - sail # mailhog: # image: 'mailhog/mailhog:latest' # ports: # - '${FORWARD_MAILHOG_PORT:-1025}:1025' # - '${FORWARD_MAILHOG_DASHBOARD_PORT:-8025}:8025' # networks: # - sail networks: sail: driver: bridge volumes: sailmysql: driver: local # sailpostgresql: # driver: local # sailredis: # driver: local 環境によってenvファイルを分ける 詳しくはこちら デフォルトで入っている.env ファイルは使わずに、 .env.local .env.stg .env.prod と環境ごとに分けた。 よし、フロントはVuetify使いたいしインストールするかぁ。。 $ ./vendor/bin/sail npm install vuetify ERROR: No such service: laravel.test あれ??? 他のモジュールをインストールしようとしても、composer require しても同じ結果だった。 原因は./vendor/laravel/sail/bin/sail にあった。 知らんかったことその1 .env ファイルを読み込みにいく設定がデフォだった。 ./vendor/laravel/sail/bin/sail (省略) if [ -f ./.env ]; then source ./.env fi (省略) 知らんかったことその2 環境変数APP_SERVICEを設定&&コンテナ名と同じにする必要がある ./vendor/laravel/sail/bin/sail (省略) # Define environment variables... export APP_PORT=${APP_PORT:-80} export APP_SERVICE=${APP_SERVICE:-"laravel.test"} # .envファイルにはAPP_SERVICEがデフォで定義されないので自動的にlaravel.test export DB_PORT=${DB_PORT:-3306} export WWWUSER=${WWWUSER:-$UID} export WWWGROUP=${WWWGROUP:-$(id -g)} (省略) ./vendor/laravel/sail/bin/sail (省略) if [ $# -gt 0 ]; then # Source the ".env" file so Laravel's environment variables are available... if [ -f ./.env ]; then source ./.env fi # Proxy PHP commands to the "php" binary on the application container... if [ "$1" == "php" ]; then shift 1 if [ "$EXEC" == "yes" ]; then docker-compose exec \ -u sail \ "$APP_SERVICE" \ # ここで$APP_SERVICEが呼ばれる php "$@" else sail_is_not_running fi (省略) 解決策 APP_SERVICEの設定 .env.local APP_SERVICE="laraevldemo" # ちなみに "" が必ず必要 コンテナを立ち上げる前に .env ファイルに .env.local ファイルの内容をコピーするコマンドを実行する Makefile up: touch .env cp .env.local .env .vendor/bin/sail up おわりに 便利機能や簡単ツールはそのメリットだけ制限や柔軟性の部分で惜しい部分があるなぁと感じましたね! 参考資料
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ajax を使ってファイルのアップロード

jQuery の ajax を使ったファイルのアップロードです。 サーバーサイドは、PHP です。 upload_ajax.html <!DOCTYPE html> <html lang="ja"> <head> <meta http-equiv="CONTENT-TYPE" content="text/html; charset=utf-8" /> <script src="/js/jquery-3.6.0.min.js"></script> <script src="upload_ajax.js"></script> <title>upload ajax</title> </head> <body> <h2>upload ajax</h2> <form id="foo"> <input id="file" name="file" type="file" /> <input id="send" type="submit" /> </form> <br /> <div id="result"></div> <br /> <hr /> <div id="outarea_aa">outarea_aa</div> <div id="outarea_bb">outarea_bb</div> <div id="outarea_cc">outarea_cc</div> <div id="outarea_dd">outarea_dd</div> <div id="outarea_ee">outarea_ee</div> <div id="outarea_ff">outarea_ff</div> <div id="outarea_gg">outarea_gg</div> <div id="outarea_hh">outarea_hh</div> <hr /> Apr/12/2021<p /> </body> </html> upload_ajax.js // --------------------------------------------------------------- // upload_ajax.js // // Apr/12/2021 // // --------------------------------------------------------------- jQuery(function () { jQuery('#foo').submit(function(){ var fd = new FormData(jQuery('#foo').get(0)) jQuery.ajax({ url: "upload_ajax.php", type: "POST", data: fd, processData: false, contentType: false, dataType: 'json' }) .done(function( data ) { var str_out = "" for (it in data.message) { str_out += data.message[it] + "<br />" } jQuery('#result').html(str_out) jQuery('#outarea_cc').text(JSON.stringify (data)) }) return false }) }) // // --------------------------------------------------------------- upload_ajax.php <?php // ------------------------------------------------------------------ // upload_ajax.php // // Apr/12/2021 // // ------------------------------------------------------------------ if ($_FILES['file']) { $size = getimagesize( $_FILES['file']['tmp_name'] ); $data = array (); $data = array( 'width' => $size[0], 'height' => $size[1] ); $filename = $_FILES['file']['name']; $tmp_name = $_FILES['file']['tmp_name']; $data['filename'] = $filename; $data['tmp_name'] = $tmp_name; $message = array (); $message[] = "*** check ***"; $path_target = "./data_work/" . $filename; $message[] = $path_target; if (move_uploaded_file ($tmp_name,$path_target) == FALSE) { $message[] = 'nothing is uploaded at ' . $_POST['now']; $message[] = $filename . " cannot be uploaded."; } else { $message[] = "*** success ***"; $message[] = $filename . " is uploaded."; } $data['message'] = $message; header('Content-type: text/html'); echo json_encode($data); } // ------------------------------------------------------------------ ?>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP8.0】function_exists('getdir')がtrueになるんだけどなにこれ?

まとめ PHP8.0.0からPHP8.0.3までの間、getdir()という組み込み関数が存在する。 Stack Overflow PHP 8, function alias compatibility getdir() こんなコードを書いたらなんかPHP8でエラーになるんだけど。 function getDir($a, $o = 2) { $d = Floor($a / $o); return ($d % 2 === 0); } んで調べてみたらgetdirはdirのエイリアスになってるみたい。 リリースノートにもエイリアスのこと全く書かれてないんだけど、なにこれ? Answer 2 getdirはPHP4時代の非常に古い関数なんだけど、最近仕様が変わったりしたのかね? Answer 4 バグレポ出したよ。 getdirはケースセンシティブだったのがケースインセンシティブになったせいかね? Answer 5 ↑ちょっと待った、ケースセンシティブは関係ないんだ。 getdir()関数はこれまでずっと存在していなかったんだ。 でもソース中にはずっと存在していたんだ。 何か深刻なことが起こっているにちがいないぞ。 PHPメーリングリスト Rowan Tommins Stack Overflowの質問https://stackoverflow.com/q/66854655/157957およびそれに伴うバグレポートhttps://bugs.php.net/bug.php?id=80914において、不可解な現象が発生しました。 PHP8.0において、dir()関数の別名としてgetdir()が誤って追加されました。 実際はもっと奇妙なことになっています。 本当はgetdir()が正しい関数名で、dir()はそのエイリアスです。 しかし、PHP7.4まではエイリアスの方の関数しか存在しませんでした。 PHP8.0においてはgetdir()は呼び出し可能な関数であり、そしてユーザが同名の関数を定義することはできません。 これは以下が原因だと思われます。 まず、dir()はPHP3から存在する関数であり、それはコンストラクタを使わないおかしなオブジェクトを生成します。 {"dir", php3_getdir, NULL}, PHPの関数名がCの関数名と一致しないため、PHP4のエイリアス機能によって以下に置き換えられます。 PHP_FALIAS(dir, getdir, NULL) しかし、これは実際にはエイリアスではありませんでした。 PHP_FEマクロにgetdirが登録されていなかったためです。 そのため、コードで実際に使用できる関数名はdirだけでした。 この状況は、PHP8でarginfoが追加されるまで続きました。 Matéはgetdir()にスタブが無いことに気が付き、それを追加してくれました。 そして20年の時を経て、ついにgetdir()に関数エントリが追加されたのです。 ZEND_FE(getdir, arginfo_getdir) ZEND_FALIAS(dir, getdir, arginfo_dir) 問題は、これをバグとみなして元に戻すべきかということです。 答え合わせはおそらく20年前に行われるべきだったもので、公開されている関数名に合わせて内部名を変更すべきでしょう。 Sara Golemon PHP_NAMED_FEってマクロは当時も存在してたのに、Zeevはどうしてそのマクロを使わなかったのでしょう。 1999年当時はZend Engine1の開発真っ最中だったからてんやわんやだったのかな。 私なら、この文書化されていない関数は、PHP8.0.0から8.0.3までに存在していたバグとして葬ります。 Rowan Tommins 異議はなかったので、プルリクエストを提出しました。 getdir()を削除し、dir()関数の内部名をdirにします。 感想 C素人なのでPHPのソース読むのつらい。 PHPの関数は、まず関数を定義して、その情報を別途インデックスに登録することで使用可能になります。 getdir()関数は、定義自体はずっと前から存在し、むしろdir()がgetdir()へのエイリアスという構造でした。 しかし、getdir()関数はインデックスに登録されていなかったので使えない状態でした。 PHP8実装に伴い気を利かせてソースを整理したら、その前世紀の遺物が意図せず現出してきたということです。 閉ざされていた古代遺跡が復活した感ありますね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[PHP] NULLか、それ以外か

概要 PHPでNULLかそれ以外かを判定するための方法をメモします。 方法 NULLの場合はNULLを返す NULL以外の場合はそれ以外を返す <?php $hoge = null; if(is_null($hoge)){ echo 'NULL'; }else{ echo 'それ以外'; } 変数が未定義の場合もNULLになります。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

実務経験に入ってから知ったLaravel/PHPの実装法まとめ

実務に入る前は知らなかったor使わなかった機能が多数用いられていた為、今後のために残していく。 一つ一つを細かに解説したものではなく、あくまでも「へーこんなのあるんだ」となるための、 まとめの記事ですのでお手柔らかに。 一貫性皆無かもしれない 間違い箇所あればガシガシ指摘お願いしますm(__)m 実務~現在まで まず実務に入ってから本記事投稿時点までで経験6ヶ月目です。 携わった(または現在も携わっている)プロジェクトにて Laravel/PHP/jQuery 自身が初めて参画した案件。 既にキックオフからは1年以上経過しており、中身のややこしさに幾度も絶望を味わう Laravel/LINEAPIでの独自API APIってすげー!!!ってなった。(語彙力) Smarty/PHP/VanilaJSでの保守・改修案件 「なるほど!わからん。」を体感 しかしおかげでほとんど知らなかった生のPHPの書き方とかもちょっと理解できた。 ※本記事は主に1つ目の案件で得た知見をまとめたものとなります。 参考までに 自身が実務に入る際は、Laravelを用いた簡単なCRUD開発ができる程度。 「SSHとSSLって何が違うん?」て聞かれて 「えーーーっとですね.....  最後がHかLかの違いです」となるレベル フロントは最低限書けるくらい。 CSSは大っ嫌いなのです 自作ヘルパー関数 Laravelには複数のグローバルなヘルパ関数が数多く存在しますが、 どこでも使える〇〇な関数あったらいいのになーと思ったとき簡単に作れてしまいます。 例:金額を引数に税込み価格を計算する関数 app/helper.phpを作成します。 (どのディレクトリでもいいです) helper.php <?php if (! function_exists('taxIncluded')) { function taxIncluded($price) { $tax = 10.0; return $price + floor($price * $tax / 100); } } せせ、先輩が作ったやつほとんどパクってる。 オートロードする autoload.filesを下記の様に編集します。 composer.json "autoload": { "files": [ "app/Http/helpers.php" ] }, オートロードとは? "https://laraweb.net/surrounding/1642/" 引用: PHPによるオートロード機能とはファイルを自動で読み込む仕組みのことです。 この機能を使うことでPHPファイルの冒頭に require を書きまくることはなくなりました。 オートロード機能を使用するには composer を使います。 composer を使用してライブラリをインストールするとvendor/autoload.phpというファイルが生成されます。 このファイルがオートロードの実体ファイルです。 このファイルを一度だけrequireすることで、vendor配下のライブラリをすべて自動的にロードしてくれます。 また、プロジェクトの直下にあるcomposer.jsonでオートロードするファイルを追加することもできます。 ↑いつもお世話になってます。 更新 $ composer dump-autoload あとは使いたいところで index.blade.php --略 <p>¥{{ number_format(taxIncluded($price)) }}(税込)</p> --略 どこでも使えます。 Eloquentモデルへのイベントをフックして何かする 例:Usersテーブルのemailが変更されたときメールを通知する モデルに$dispatchesEventsプロパティを定義する App\User.php use App\Events\UserUpdated; protected $dispatchesEvents = [ 'email' => UserUpdated::class ]; イベントクラスを作成する $ php artisan make:event UserUpdated 行いたい処理をイベントクラスに記述する App\Events\UserUpdated.php namespace App\Events; use App\Models\User; class UserUpdated { use Dispatchable, InteractsWithSockets, SerializesModels; public function __construct(User $user) {  /*メール送信処理を書く(詳しくはwebで)*/ } } こんな感じで簡単にフックできます。 ただ処理の中でEloquent\Model経由で何かしらすると再帰するので要注意とのこと。 いやー便利だけど難しい。 自作artisanコマンドを作る 画面作るまでも無いけど〇〇な処理ササッとできやんかなーというあなたに朗報です まずコマンド一覧確認 $ php artisan list ご親切なことに僕の嫌いな英語で各コマンドの説明がずらーっと 自作コマンド作成!! $ php artisan make:command SampleCommand app\Console\Command\SampleCommandが出来ました。 さて、ここになんやかんや書いていきます。 名前を変更 SampleCommand.php //ここを protected $signature = 'command:name'; //こうじゃ protected $signature = 'email:send {user_id}'; {}で引数の指定ができます。 また「:」をつけることで一覧でグルーピングして表示されます。 (無くでもOK) また、↑の場合は必須引数のため、引数抜きでコマンド実行すると怒られます 任意の引数の場合はこんな感じに。 SampleCommand.php protected $signature = 'email:send {user_id?}'; //指定されなかった場合のデフォルト値を指定 protected $signature = 'email:send {user_id=1}'; 引数に名前指定したり、オプションの指定もしたりできますが、 長くなるので詳しくはGoogle先生に尋ねてください。(投げやり) コマンドの説明 SampleCommand.php protected $description = 'メール送信する' 何をするコマンドか書いておきます。 引数取得 SampleCommand.php public function handle() { $userId = $this->argument("user_id"); $this->sendMail($userId); } あとは処理書いていけばokです 他にもオプション設定したり、なんやかんや色々できるので詳しくはググってください。 中断
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP-CS-FIXERでコマンドライン引数でパスを指定すると構成ファイルのパスが無視される

タイトル通り。 環境 PHP-CS-FIXER: 2.18 内容 By default --path-mode is set to override, which means, that if you specify the path to a file or a directory via command arguments, then the paths provided to a Finder in config file will be ignored. You can use --path-mode=intersection to merge paths from the config file and from the argument: PHP-CS-FIXERでコマンドライン引数でパスを指定すると構成ファイルのパスが無視される。 ちなみに、オーバーライドする状態で実行すると、 Paths from configuration file have been overridden by paths provided as command arguments. が出力される。 所感 コマンドライン引数と構成ファイルのパスをマージしたいユースケースが思い浮かばない。基本的に構成ファイルで管理して、コマンドはシンプルにしておくべきだろう。 参考 PHP-CS-Fixer/usage.rst at 2.18 · FriendsOfPHP/PHP-CS-Fixer
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

php-fpm + apache環境での環境変数の持たせ方

php-fpm環境下でApache httpdのSetEnvで設定された環境変数は、PHPのenv()等では取得できるが、 execで実行されるコマンドには、SetEnvで設定された環境変数が反映されなかったので(php-fpmの仕様?)実施した回避策を書く! 要約 ApacheのSetEnvは使わず/etc/environmentに環境変数を記載して利用する /etc/environmentの環境変数利用手順 /etc/systemd/system/httpd.serviceを作成 以下内容で作成する .include /lib/systemd/system/httpd.service [Unit] After=network.target remote-fs.target nss-lookup.target httpd-init.service cloud-config.service [Service] UMask=002 EnvironmentFile=/etc/environment /etc/systemd/system/php-fpm.serviceを作成 以下内容で作成する .include /lib/systemd/system/php-fpm.service [Unit] After=syslog.target network.target cloud-config.service [Service] UMask=002 EnvironmentFile=/etc/environment PrivateTmp=false /etc/php-fpm.d/www.confに1行追加 以下を追記 clear_env = no あとは/etc/environmentに環境変数を記載していくだけ!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

##Cookieとセッションについて

〜アウトプットメモ〜 前提知識 ・HTTPの理解必要 ・リクエスト、レスポンスなどの理解 ・HTTPはリクエストし、レスポンスする、この1往復で通信が切断される→以前の状態を全く覚えていない。これをステートレスと言う。 ・ステートフルにするには、サーバーがクライエントに対して識別できる一意の値を渡し、クライエントはリクエストする時にその値を教えてあげればサーバー側で識別できるようになる。この役割を果たしているのがCookie(クッキー)。 Cookieについて ・クライアントに保存された情報のこと <初回> ①リクエスト ②レスポンス(Cookieを保存してください) ③レスポンスの指示に従い、パソコンにCookieを保存 <2回目> ①リクエスト(保存しているCookieの情報も送信) ②レスポンス ・具体的にサーバーはレスポンスメッセージにSet-Cookieヘッダを付与することで、クライエントに対して「Cookieを保存してください」と指示する事が可能。Set-CookieヘッダにはCookieの有効期限やCookieを送るドメイン、有効パスなどの各属性があり。 ・クライアントは、リクエストメッセージにCookieヘッダを付与する事で、 「このようなCookieが保存されています」と教える。 ・Set-Cookieヘッダの定義 setcookie(Cookie名, Cookie値, 有効日時, パス, ドメイン, HTTPS接続のみ, Javascript無効) ・PHPでCookieを取得する $_COOKIE = array( 'name' => 'sato'; ) $name = $_COOKIE['name']; echo $name; 連想配列に格納された値を取得するときは$変数名[キー]のように記述する。 セッションについて ・セッションとは、一連の処理の始まりから終わりまでを表す概念のこと。 ・PHPでセッション開始するにはsession_start();関数を利用します。 ・セッションを管理するには、Cookieに一意の値を入れて、リクエストしてもらうことで、一連の処理として扱える。この一意の値の役割をするのがセッションID。 ・session_start()を記述だけで、自動でセッションIDを発行してくれる。 <リクエストメッセージにセッションIDがない場合> ・セッションIDを発行し、セッションIDをCookieに保存するようにレスポンスメッセージを送信 ・セッションIDを発行する時に、サーバー側ではセッションIDごとにセッションファイルを作成 <リクエストメッセージにセッションIDがある場合> ・セッションIDがあれば、該当するセッションファイルにある情報を参照
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPStorm でペアプロが捗る共同編集機能使ってみた

これは何 PHPStorm 2021.1 で導入された、Code With Me 機能を使ってみました。 自分のPHPStormのファイルたちを、他の人がリアルタイムでいじることができます。 早速使ってみました! 使い方 招待する人も、招待される人も新しいPHPStormにする ホストになる人が権限設定して招待URLを発行する ゲストになる人はURLクリックする ホストになった人はAcceptする マイクや映像は画面上部のアイコンから on/off 画面上部のアイコンから、編集中の人にfocusすることができる。強制的に「自分のところをみろ!」もできる 感想 今まではペアプロやるにしても Google Meet や Around の画面共有で、口頭で「こここうやって直してください」とか話していたのが、「こうやって書くといいですよ」 と見せるのが簡単になります。コミュニケーションコストが下がりそうです。 最高! 使ってみてわかった問題点 日本語入力はちらつくのでいまいち。また、同時編集に向かない。アルファベット入力は概ね問題なし。 音声や画像のトラブルあり。繋ぎ直すと大体治った。 特定のマイクではPCごと落ちるケースも。 ホストは人が入るたびに accept するのが面倒
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPStorm でペアプロが捗る共同編集機能使ってみた(Code With Me!)

これは何 PHPStorm 2021.1 で導入された、Code With Me 機能を使ってみました。 自分のPHPStormのファイルたちを、他の人がリアルタイムでいじることができます。 早速使ってみました! 使い方 招待する人も、招待される人も新しいPHPStormにする ホストになる人が権限設定して招待URLを発行する ゲストになる人はURLクリックする ホストになった人はAcceptする マイクや映像は画面上部のアイコンから on/off 画面上部のアイコンから、編集中の人にfocusすることができる。強制的に「自分のところをみろ!」もできる 感想 今まではペアプロやるにしても Google Meet や Around の画面共有で、口頭で「こここうやって直してください」とか話していたのが、「こうやって書くといいですよ」 と見せるのが簡単になります。コミュニケーションコストが下がりそうです。 最高! あとは、別のファイルを編集することも可能なので、一人がテスト書いて、一人が実装かいて、みたいなこともできそうです。最高! 使ってみてわかった問題点 日本語入力はちらつくのでいまいち。また、同時編集に向かない。アルファベット入力は概ね問題なし。 音声や画像のトラブルあり。繋ぎ直すと大体治った。 特定のマイクではPCごと落ちるケースも。 ホストは人が入るたびに accept するのが面倒
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PhpStorm でペアプロが捗る共同編集機能使ってみた(Code With Me!)

これは何 PhpStorm 2021.1 で導入された、Code With Me 機能を使ってみました。 自分のPhpStormのファイルたちを、他の人がリアルタイムでいじることができます。 早速使ってみました! 使い方 招待する人も、招待される人も新しいPhpStormにする ホストになる人が権限設定して招待URLを発行する ゲストになる人はURLクリックする ホストになった人はAcceptする マイクや映像は画面上部のアイコンから on/off 画面上部のアイコンから、編集中の人にfocusすることができる。強制的に「自分のところをみろ!」もできる 感想 今まではペアプロやるにしても Google Meet や Around の画面共有で、口頭で「こここうやって直してください」とか話していたのが、「こうやって書くといいですよ」 と見せるのが簡単になります。コミュニケーションコストが下がりそうです。 最高! あとは、別のファイルを編集することも可能なので、一人がテスト書いて、一人が実装かいて、みたいなこともできそうです。最高! 使ってみてわかった問題点 日本語入力はちらつくのでいまいち。また、同時編集に向かない。アルファベット入力は概ね問題なし。 音声や画像のトラブルあり。繋ぎ直すと大体治った。 特定のマイクではPCごと落ちるケースも。 ホストは人が入るたびに accept するのが面倒
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Toml & Python & PHP & vue & levelDB でSSL証明書の有効期限を毎日チェック

前置き 我々のような受託システム開発会社は、開発依頼を受ける度に、さまざまなドメインにそのシステムをロンチしていきます。 常時SSLが当たり前となった今日において、そのドメインの数だけSSL証明書が必要になります。 そしてSSL証明書にはLet's encryptを採用するケースも多いため、その更新期限管理は定期的なチェックが欠かせません。 (バッチで自動更新は当然としても) うちではもうなんだかんだと管理している客先ドメインが100超になっているので、日次バッチで全ドメインの有効期限を取得して、これが一覧画面から確認できるようにしておくことで、ある日突然サイトにアクセスできなくなって大慌てで証明書を更新しなけれけばならないような事態に未然対策しています。 本題 というのはまあいいとして、ここでの趣旨は、このようなワンオペサービスの裏側で実装される数々の周辺技術を束ねてひとつのアプリケーションとして構築する醍醐味感、のようなものになると思います。 目的はひとつでもそれを実現するための中間過程はいくつも存在し、それぞれを実現するための手段も多岐に及ぶため、適材適所な取捨選択をしていくのであれば応用技術の醍醐味がやってくるのは当然なのです。 登場人物 crontab スクリプトを定期実行されるためのスケジューラ。実体はシェル ここではドメインの有効期限を日次バッチで取得するための設定に使用 levelDB キーバリューストアな軽量ストレージ。使用頻度の高いものを優先に階層的なインデックスをおこなうのが特徴 ここでは日次バッチで取得した各ドメインの有効期限をFQDN単位で記録するのに使用 openSSL SSL証明書等の暗号プロトコルを触るためのデファクトスタンダード ここでは外部SSL証明書のパースに使用 python 昔からあるけど最近超花形言語として返り咲いた万能言語(3.7からハッシュが順番を保証してくれるようになったので私も3.7から大好き) ここではcrontabをトリガーにopenSSLで取得した有効期限をlevelDBに登録するためのバッチスクリプトとして使用 PHP 昔からあるけど今でも人気なWEB開発言語(私はずっと大好き) ここではバッチで記録した全ドメインの有効期限を後述のVueにAPIとして提供するのに使用 Vue JSフレームワークの雄。SPAや簡単なアプリケーションなら相性抜群 ここではフロントエンドの更新期限一覧画面として使用 nginx スクリプトをWEB通信規格を経由して提供するためのミドルウェア ここではPHPとVueをそれぞれインターフェースするのに使用 toml 設定ファイルのマークアップ言語。可読性がよく様々な言語にもライブラリが提供されているが、まだダークホース感有 ここでは各言語を横断してDRYな設定を管理するのに使用 醍醐味 以下、さっそくです。 前提 pwd # 適宜読み替えてください /home/you/projects/ssl-check tree -L 2 -I node_modules # 最終的な成果物 +__ api | +__ composer.json | +__ index.php | L__ vendor +__ app | +__ README.md | +__ babel.config.js | +__ dist | +__ package.json | +__ public | +__ src | L__ vue.config.js +__ batch | L__ ssl_check.py +__ configs | L__ common.toml +__ logs +__ package.json L__ results +__ 000005.ldb +__ 000006.log +__ CURRENT +__ LOCK +__ LOG +__ LOG.old L__ MANIFEST-000004 crontab 5 4 * * * cd /home/you/projects/ssl-check/batch/ && /usr/local/bin/python3.7 ssl_check.py & > /dev/null 2>&1 levelDB # for PHP sudo apt-get install libleveldb-dev cd /usr/local/src/ git clone https://github.com/reeze/php-leveldb.git cd php-leveldb/ phpize ./configure --prefix=/home/you/.phpenv/versions/7.4.0/lib/php/leveldb --with-leveldb=/home/you/.phpenv/versions/7.4.0/include/php/include/leveldb --with-php-config=/home/you/.phpenv/versions/7.4.0/bin/php-config make make install vi ~/.phpenv/versions/7.4.0/etc/php.ini extension=/home/you/.phpenv/versions/7.4.0/lib/php/extensions/no-debug-non-zts-20180731/leveldb.so sudo service php-fpm restart # for python sudo pip install plyvel pip list | grep plyvel plyvel 1.3.0 toml # for PHP cd api/ composer require yosymfony/toml # for python sudo pip install toml pip list | grep toml toml 0.10.2 configs/common.toml APP_DIR = "/home/you/projects/ssl-check/" RESULT_DB = "results" CHECK_CMD = "openssl s_client -connect {fqdn}:443 -servername {fqdn} </dev/null 2>/dev/null | openssl x509 -text | grep \"Not After\"" STATUS_OK = 1 STATUS_NOTE = 2 STATUS_NG = 3 STATUS_ERROR = 4 # ↓適宜編集 [DOMAIN_LIST] "example.com" = [ "example.com", "test.example.com", ] "google.com" = [ "google.com", ] "yahoo.co.jp" = [ "yahoo.co.jp", ] python batch/ssl_check.py import logging import os import sys import logging import subprocess import datetime import calendar import pytz import dateutil.parser import pickle import click import plyvel import json import toml configs = toml.load(open('../configs/common.toml')) logger = logging.getLogger('Batch') logger.setLevel(10) fh = logging.FileHandler(configs['APP_DIR'] + 'logs/batch.log') logger.addHandler(fh) sh = logging.StreamHandler() logger.addHandler(sh) format = logging.Formatter('%(asctime)s - [%(levelname)s] (%(lineno)d) %(message)s') fh.setFormatter(format) sh.setFormatter(format) curr_tz = pytz.timezone('Asia/Tokyo') curr_ts = int(datetime.datetime.now().timestamp()) results = {}; index = 0; for brand in configs['DOMAIN_LIST']: logger.info(brand + ' >>> start') results[brand] = {} for fqdn in configs['DOMAIN_LIST'][brand]: try: limit_at = subprocess.check_output(configs['CHECK_CMD'].format(fqdn = fqdn), shell = True) index += 1 if limit_at != '': limit_at = str(limit_at).split(' : ')[1] limit_at = limit_at.split('\\n')[0] limit_at = dateutil.parser.parse(limit_at) limit_ts = calendar.timegm(limit_at.timetuple()) if limit_ts < curr_ts: status = configs['STATUS_NG'] elif limit_ts < curr_ts - (60 * 60 * 24 * 30): status = configs['STATUS_NOTE'] else: status = configs['STATUS_OK'] limit_at = limit_at.astimezone(curr_tz).replace(tzinfo=curr_tz) limit_at = str(limit_at).split('+')[0].replace('-', '/') results[brand][fqdn] = { 'index': index, 'status': status, 'limit_at':limit_at } else: logger.warning(fqnd + ' unable to load certificate') results[brand][fqdn] = { 'index': index, 'status': configs['STATUS_ERROR'], 'limit_at':None } except Exception as e: logger.warning(e) results[brand][fqdn] = { 'index': index, 'status': configs['STATUS_ERROR'], 'limit_at':None } logger.info(brand + ' <<< end') logger.debug(results) try: plyvel.destroy_db(configs['APP_DIR'] + configs['RESULT_DB']) result_db = plyvel.DB(configs['APP_DIR'] + configs['RESULT_DB'], create_if_missing=True) for brand in results: for fqdn, result in results[brand].items(): result_db.put(str(fqdn).encode(), json.dumps(result).encode()) except Exception as e: logger.warning(e) finally: result_db.close() PHP api/index.php <?php require_once 'vendor/autoload.php'; use Yosymfony\Toml\Toml; $configs = Toml::ParseFile(dirname(__FILE__) . '/../configs/common.toml'); $db = new LevelDB($configs['APP_DIR'] . $configs['RESULT_DB'], ['create_if_missing' => true]); $results = []; foreach ($configs['DOMAIN_LIST'] as $brand => $list) { isset($results[$brand]) or $results[$brand] = []; foreach ($list as $fqdn) { $result = $db->get($fqdn); $results[$brand][$fqdn] = $result; } } $checked_at = date('Y/m/d H:i:s', filemtime($configs['APP_DIR'] . $configs['RESULT_DB'])); echo json_encode(['list' => $results, 'checked_at' => $checked_at], JSON_UNESCAPED_UNICODE); Vue app/vue.config.js module.exports = { lintOnSave: false, publicPath: 'https://ssl-check.yourdomain.com/', devServer: { host: 'localhost', port: 8030, disableHostCheck: true, public: 'https://ssl-check.yourdomain.com/', } } app/package.json { "name": "app", "version": "0.1.0", "private": true, "scripts": { "serve": "vue-cli-service serve", "build": "vue-cli-service build", "lint": "vue-cli-service lint" }, "dependencies": { "axios": "^0.21.1", "bootstrap": "^4.6.0", "bootstrap-vue": "^2.21.2", "core-js": "^3.6.5", "register-service-worker": "^1.7.2", "vue": "^2.6.11", "vue-meta": "^2.4.0" }, "devDependencies": { "@vue/cli-plugin-babel": "~4.5.0", "@vue/cli-plugin-eslint": "~4.5.0", "@vue/cli-service": "~4.5.0", "babel-eslint": "^10.1.0", "eslint": "^6.7.2", "eslint-plugin-vue": "^6.2.2", "vue-template-compiler": "^2.6.11" }, "eslintConfig": { "root": true, "env": { "node": true }, "extends": [ "plugin:vue/essential", "eslint:recommended" ], "parserOptions": { "parser": "babel-eslint" }, "rules": {} }, "browserslist": [ "> 1%", "last 2 versions", "not dead" ] } app/src/configs/common.js export default Object.freeze({ CNAME: 'SSL証明書 更新状況一覧', CURL: 'https://ssl-check.yourdomain.com/', }); app/src/main.js import Vue from 'vue' import { BootstrapVue, IconsPlugin } from 'bootstrap-vue' import App from './App.vue' import axios from 'axios' import './registerServiceWorker' import VueMeta from 'vue-meta' Vue.use(VueMeta) Vue.use(BootstrapVue) Vue.config.productionTip = false Vue.prototype.$axios = axios new Vue({ render: h => h(App), }).$mount('#app') app/src/App.vue <template> <div id="app"> <Ssl/> </div> </template> <script> import 'bootstrap/dist/css/bootstrap.css' import 'bootstrap-vue/dist/bootstrap-vue.css' import Configs from './configs/common' import Ssl from './components/Ssl.vue' export default { metaInfo: { title: Configs.CNAME, titleTemplate: Configs.CNAME, htmlAttrs: { lang: 'ja', amp: true }, meta: [ { charset: 'utf-8' }, { name: 'application-name', content: Configs.CNAME }, { name: 'robot', content: 'noindex,nofollow' }, { name: 'author', content: 'ketoha' }, { name: 'copyright', content: '&copy;ketoha' }, { name: 'og:site_name', content: Configs.CNAME }, { name: 'og:url', content: Configs.CURL }, { name: 'og:title', content: Configs.CNAME } ] }, name: 'App', components: { Ssl } } </script> <style> @import "../public/index.css"; </style> app/src/components/Ssl.vue <template> <div> <h1>SSL証明書 更新状況一覧<span>{{ checked_at }}</span></h1> <table> <thead> <tr> <th>#</th><th>##</th><th>ドメイン</th><th>FQDN</th><th>ステータス</th><th>期限終了日時</th> </tr> </thead> <tbody> <template v-for="(data, brand, pidx) in list"> <tr v-for="(result, fqdn, sidx) in data"> <td>{{ pidx+1 }}</td> <td>{{ sidx+1 }}</td> <td>{{ brand }}</td> <td>{{ fqdn }}</td> <td v-if="result.status"> <span v-if="result.status === 1" class="ok">正常</span><span v-if="result.status === 2" class="note">間近</span><span v-if="result.status === 3" class="ng">失効</span><span v-if="result.status === 4" class="error">失敗</span> </td><td v-else>-</td> <td v-if="result.limit_at">{{ result.limit_at }}</td><td v-else>-</td> </tr> </template> </tbody> </table> </div> </template> <script> export default { name: 'Ssl', data: function(){ return { list:{}, checked_at:null, is_error:false } }, mounted:function() { window.addEventListener('DOMContentLoaded', this.getList) }, methods: { getList:function(){ document.body.classList.add('loading') this.$axios.get('https://ssl-check.ketoha.xyz/api/').then(function(response){ this.list = {} this.checked_at = response.data.checked_at let list = response.data.list //console.log(list) for (let brand in list) { this.list[brand] = {} for (let fqdn in list[brand]) { this.list[brand][fqdn] = JSON.parse(list[brand][fqdn]) } } }.bind(this)).catch(function(error){ this.is_error = true }.bind(this)).finally(function(){ document.body.classList.remove('loading') }.bind(this) )} } } </script> nginx server { listen 80 default; server_name ssl-cjeck.yourdomain.com; return 301 https://$host$request_uri; } server { listen 443 ssl http2; server_name ssl-cjeck.yourdomain.com; ssl_certificate /etc/letsencrypt/live/ssl-check.yourdomain.com/fullchain.pem; ssl_certificate_key /etc/letsencrypt/live/ssl-check.yourdomain.com/privkey.pem; root /home/you/projects/ssl-check/app/dist; index index.html; access_log /home/you/projects/ssl-check/logs/access.log; error_log /home/you/projects/ssl-check/logs/error.log; location / { root /home/you/projects/ssl-check/app/dist; index index.html; } location /api/ { root /home/you/projects/ssl-check/api; index index.php; try_files $uri $uri/ /index.php?$args; } location ~ \.php$ { root /home/you/projects/ssl-check/api; index index.php; try_files $uri = 404; fastcgi_split_path_info ^(.+\.php)(/.+)$; fastcgi_pass unix:/home/you/.phpenv/versions/7.4.0/var/run/php-fpm.sock; fastcgi_index index.php; fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; include fastcgi_params; } } 最後に 適材適所した結果、毎日このような画面で更新期限管理ができるようになります。 ※画面にはないですが、ここでは有効期限が切れている場合は赤で、一ヶ月を切っている場合はオレンジで表示されるようになっています。 オレンジを検知した場合はメールで通知、とかするともっといいかもしれません。 技術の応用しかしていない身としては、日々OSSでソリューションを提供してくれる先人たちには感謝しかありません。 しっかり活用していきたいものですね。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP5上級試験/準上級試験の上級合格に挑戦(20) プログラミングPHP第3版 14章~15章

14章 さまざまなプラットフォームでのPHP ・黒本13章「WindowsでのPHP」が対応 ・Zend Server CE(Community Edition)でマルチプラットフォーム対応 14.1.1 実行環境の調べ方 PHP_OSの他にphp_uname()がある →OS情報がPHP_OSよりも多い 14.1.2 複数プラットフォームに対応するパス PHP4.07以降、WinのUNCパスにもスラッシュを使用できる。 ※UNCパスとは、Windowsネットワーク上で共有されている様々な資源(ファイルやフォルダ、プリンタなど)の位置を表記する標準的な記法で、「\コンピュータ名\資源の共有名\資源内での位置」(英語環境では\はバックスラッシュ)という形式で表される。 14.1.4 メール送信 Unixシステムではmail()で、sendmailかQmailのどちらを使うかを切り替えられる Windows上でsendmailを使う場合、インストールしてphp.iniのsendmai_pathを設定する メールソフトでメール送信用に使っているSMTPサーバーを指定するのが簡単 14.1.6 ファイル終端の扱い Winのテキストファイルの最後にはControl-Z("\xlA")という制御コードが付加される Unixはファイルのデータとは別にファイルサイズについての情報が格納される →Windowsのテキストファイルでもfeof()が使える 14.2 COMインターフェースの使用 COMを使うと他のWindowsアプリを制御できる。たとえばファイルの内容をExcelに送ってグラフ変換、GIF画像としてエクスポートする、、、なんてことができる また入力フォームから受け取った情報をWordで整形して請求書印刷。。。なんてこともできる 14.2.1 背景知識 COMとは、リモートプロシージャコール(RPC)の仕組みにいくつかのオブジェクト指向の機能を追加したもの コール元のプログラム(コントローラ)から別のプログラム(COMサーバー、つまりオブジェクト)を呼び出せる 同一マシンにあるプログラムを呼び出すときはCOM、リモートマシンのプログラムを呼び出す時は分散COM(DDOM)を使う DLLとして提供されているコードが同じプロセス空間に読み込まれる場合、そのCOMサーバーはプロセス(inproc)サーバーになる。そのコード辞退が単体のアプリケーションとして独自のプロセス空間で動作する場合は、プロセス外サーバー(ローカルサーバーアプリケーション)と呼ばれる OLE(Object Linking and Embedding)はMicorosoftが以前に使用していたあるオブジェクトを別のオブジェクトに埋め込む技術。(ExcelシートをWord文書に埋め込むとか) 前はDDE(Dynamic Data Exchange)を使っていたため機能が限られていた いまはCOMを使っている PHPによるWord文書を作成してHello,Worldという文字を追加する例 これをコマンドラインから起動する index.php $word = new COM("word.application") or die("Wordの起動に失敗しました"); echo "Word バージョン{$word->Version}を起動しました<br>"; //新規作成 $word->Documents->add(); //Hello,World記入 $word->Selection->typeText("Hello,World"); $word->Documents[1]->SaveAs("c:/php_com_test.doc"); //Word終了 $word->quit(); //Word変数解放 $word = null; echo "end"; 14.2.3 APIの調べ方 Wordなどのオブジェクト階層やパラメータを調べるにはMicrosoftの開発者向けサイトを利用する。 他のアプリも同じ。 15章 Webサービス 内容的には黒本の16章のJSONが対応する 15.1 RESTクライアント RESTfulウェブサービス・・・HTTPを使って、REST原則に従ったウェブAPIを実装したサービス全般 ちなみにAPIとはApplication Programming Interfaceで、簡単に言うと他のソフトの機能を連携して使えるようにする機能 @NagaokaKenichi さんの記事がとってもわかりやすい。ありがとうございます! REST APIの多くはAPIからのレスポンスをJSON形式で返すことが多い JsonSerializableインタフェースを使えば、オブジェクトをお好みのJSON形式に変換できる 15.1 リソースの取得・更新・作成・削除 cURL関数(HTTPリクエストをすることにより、外部サイトの情報を取得することができる関数)を使う curl_init() cURLのセッションを初期化し、cURLハンドルを返す curl_setopt() cURLの転送用オプションを設定。boolean型の値を返す curl_exec() cURLのセッションの実行時に使用。ただし、セッションの初期化、オプション設定が終わってから。 curl_close() cURLのセッションを閉じる GET/POST/PUT/DELETEは、curl_setopt()のほうで設定する http_build_query(data, prefix, seperator, encode) はURL エンコードされたクエリ文字列を生成する curl_getInfo()は指定したリソースの情報をゲットする index.php // curl_closeの前にvar_dumpで$resを調べると良いと思う //基本************************************* $url = "https://www.xxx.net/xxx/"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $res = curl_exec($ch); curl_close($conn); //GET ************************************* $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); $res = curl_exec($ch); curl_close($conn); //POST ************************************* $url = "http://www.google.co.jp/"; $ch = curl_init(); $data = array('qiita' => 1); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); $res = curl_exec($ch); curl_close($ch); //PUT ************************************* //ファイルアップロードを想定 $bookid = "PHPProgramming"; $url = "http://www.xxx.xx.jp/{$bookid}"; $data = json_encode(array('edition' => 3)); $requestData = http_build_query($data, '', '&'); $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); $fh = fopen("php://memoriy", 'rw'); fwrite($fh, $requestData); rewind($fh); curl_setopt($ch, CURLOPT_INFILE, $fh); curl_setopt($ch, CURLOPT_INFILESIZE, mb_strlen($requestData); curl_setopt($ch, CUPLOPT_PUT, true); curl_setopt($ch, CURLOPT_POST, true); curl_setopt($ch, CURLOPT_POSTFIELDS, $data); $res = curl_exec($ch); $resInfo = curl_getinfo($ch); fclose($fh); //DELETE ************************************* $bookid = "PHPProgramming"; $url = "http://www.xxx.xx.jp/{$bookid}"; $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_CUSTOMERREQUEST, 'DELETE'); $result = curl_exec($ch); $resultInfo = curl_getinfo($ch); curl_close(); 15.2 XML_RPCとSOAP ウェブサービスを作るときによく使われる標準的なプロトコル。 黒本だと、第9章XMLで紹介 PHPだと、xmlrpcモジュールを使うとSOAP・XML-RPCの両方を利用できる
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPからFortigate REST APIを用いてDHCPコンフィグ情報を取得する

はじめに 趣味でFortiGateのREST APIを勉強しています。 今回はFortiGateのREST APIにてDHCP関連の以下の情報をPHPで取得する方法について紹介します。 (1) FortiGateからDHCPで払い出しているIPアドレスのリストを取得 (2) FortiGateのDHCPコンフィグ情報を取得 環境 FortiGate: FG-60D, ファームウェア:v6.0.10 PHP:PHP 8.0.3 (cli) コード fgApiTest.php <?php $fghost = "ip address"; $fglogin = "login id"; $fgpass = "login password"; $url = 'https://'.$fghost.'/logincheck'; $data = array('username'=>$fglogin,'secretkey'=>$fgpass); $post_data = http_build_query($data); $curl_connection = curl_init($url); curl_setopt($curl_connection, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($curl_connection, CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt($curl_connection, CURLOPT_POST, TRUE); curl_setopt($curl_connection, CURLOPT_POSTFIELDS, $post_data); curl_setopt($curl_connection, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($curl_connection, CURLOPT_HEADER, TRUE); $response = curl_exec($curl_connection); preg_match_all('/^Set-Cookie:\s*([^;]*)/mi', $response, $matches); // (1) DHCPで払い出しているIPアドレスのリストを取得 $curl_connection = curl_init('https://'.$fghost.'/api/v2/monitor/system/dhcp/'); curl_setopt($curl_connection, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($curl_connection, CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt($curl_connection, CURLOPT_COOKIE, $matches[1][0]); $response = curl_exec($curl_connection); echo ($response); // (2) DHCPに関するコンフィグ情報を取得 $curl_connection = curl_init('https://'.$fghost.'/api/v2/cmdb/system.dhcp/server'); curl_setopt($curl_connection, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($curl_connection, CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt($curl_connection, CURLOPT_COOKIE, $matches[1][0]); $response = curl_exec($curl_connection); echo ($response); curl_close($curl_connection); まとめ (1)DHCPで払い出しているIPアドレスのリストを取得 - CUIの「execute dhcp lease-list」のような結果を取得可能 \$curl_connection = curl_init('https://'.$fghost.'/api/v2/monitor/system/dhcp/'); (2) DHCPに関するコンフィグ情報を取得 - CUIの「show system dhcp serve」のような結果を取得可能 \$curl_connection = curl_init('https://'.$fghost.'/api/v2/cmdb/system.dhcp/server'); 所感 FortiGateのREST APIの情報はインターネット上で公開されている情報が少なく、 情報を集めるのに苦労しました 「(1)DHCPで払い出しているIPアドレスのリストを取得」は色々と試しているうちに発見できましたが、 「(2) DHCPに関するコンフィグ情報を取得」の "system.dhcp" という書き方は自力では思いつくことができず、 インターネットを2時間程度彷徨い、参考サイト[2]のスウェーデンのサイト(?)で 情報を発見することがでました。 インターネットは偉大 FortiGate REST APIの詳しい情報は 「Fortinet Developer Network(FNDN)開発者コミュニティ」で提供されているようですが、 このサイトに登録するためにはFortinetの従業員2名以上にスポンサーになってもらう必要があるようで、 趣味でFortiGate REST APIをお勉強している者にとってはハードルが高すぎです。。。 参考 [1] PHPからFortinet REST APIの利用方法 Rest api usage | Fortinet Technical Discussion Forums, 2021/4/12アクセス [2] Fortinet REST APIでDHCPに関するコンフィグ情報の取得方法 Fortigate API – FortiOS 6.2 – Balanced, 2021/4/11アクセス [3]FNDNサイト Fortinet Developer Network(FNDN)開発者コミュニティ - フォーティネット
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Fortigate REST APIでDHCPコンフィグ情報を取得する

はじめに/結論 趣味でFortiGateのREST APIのお勉強しています。 今回はFortiGateのREST APIにてDHCP関連の以下の情報をPHPで取得する方法について紹介します。 ※この記事はPHPについて書いていますが、  REST APIのURLはどの言語でも変わりませんので、最初に結論のURLも書いておきます。 (1) FortiGateからDHCPで払い出しているIPアドレスのリストを取得 https://"FortiGateのIPアドレス"/api/v2/monitor/system/dhcp (2) FortiGateのDHCPコンフィグ情報を取得 https://"FortiGateのIPアドレス"/api/v2/cmdb/system.dhcp/server 環境 FortiGate: FG-60D, ファームウェア:v6.0.10 PHP:PHP 8.0.3 (cli) コード fgApiTest.php <?php $fghost = "ip address"; $fglogin = "login id"; $fgpass = "login password"; $url = 'https://'.$fghost.'/logincheck'; $data = array('username'=>$fglogin,'secretkey'=>$fgpass); $post_data = http_build_query($data); $curl_connection = curl_init($url); curl_setopt($curl_connection, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($curl_connection, CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt($curl_connection, CURLOPT_POST, TRUE); curl_setopt($curl_connection, CURLOPT_POSTFIELDS, $post_data); curl_setopt($curl_connection, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($curl_connection, CURLOPT_HEADER, TRUE); $response = curl_exec($curl_connection); preg_match_all('/^Set-Cookie:\s*([^;]*)/mi', $response, $matches); // (1) DHCPで払い出しているIPアドレスのリストを取得 $curl_connection = curl_init('https://'.$fghost.'/api/v2/monitor/system/dhcp/'); curl_setopt($curl_connection, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($curl_connection, CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt($curl_connection, CURLOPT_COOKIE, $matches[1][0]); $response = curl_exec($curl_connection); echo ($response); // (2) DHCPに関するコンフィグ情報を取得 $curl_connection = curl_init('https://'.$fghost.'/api/v2/cmdb/system.dhcp/server'); curl_setopt($curl_connection, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($curl_connection, CURLOPT_SSL_VERIFYHOST, FALSE); curl_setopt($curl_connection, CURLOPT_COOKIE, $matches[1][0]); $response = curl_exec($curl_connection); echo ($response); curl_close($curl_connection); まとめ (1)DHCPで払い出しているIPアドレスのリストを取得 - CUIの「execute dhcp lease-list」のような結果を取得可能 \$curl_connection = curl_init('https://'.$fghost.'/api/v2/monitor/system/dhcp/'); (2) DHCPに関するコンフィグ情報を取得 - CUIの「show system dhcp serve」のような結果を取得可能 \$curl_connection = curl_init('https://'.$fghost.'/api/v2/cmdb/system.dhcp/server'); 所感 FortiGateのREST APIの情報はインターネット上で公開されている情報が少なく、 情報を集めるのに苦労しました 「(1)DHCPで払い出しているIPアドレスのリストを取得」は色々と試しているうちに発見できましたが、 「(2) DHCPに関するコンフィグ情報を取得」の "system.dhcp" という書き方は思いつくことができず、 インターネットを2時間程度彷徨い、参考サイト[2]のスウェーデンのサイトで 情報を発見することがでました。 インターネットは偉大 FortiGate REST APIの詳しい情報は 「Fortinet Developer Network(FNDN)開発者コミュニティ」で提供されているようですが、 このサイトに登録するためにはFortinetの従業員2名以上にスポンサーになってもらう必要があるようで、 趣味でFortiGate REST APIをお勉強している者にとってはハードルが高すぎです。。。 参考サイト [1] PHPからFortinet REST APIの利用方法 Rest api usage | Fortinet Technical Discussion Forums, 2021/4/12アクセス [2] Fortinet REST APIでDHCPに関するコンフィグ情報の取得方法 Fortigate API – FortiOS 6.2 – Balanced, 2021/4/11アクセス [3]FNDNサイト Fortinet Developer Network(FNDN)開発者コミュニティ - フォーティネット, 2021/4/11アクセス
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む