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

?インターネット老人?のためのホームページ(死語)リフォーム術

この記事の対象 ~00年代初頭にホームページ作っていて、現在放置中……という人、あるいはそういう人から依頼されて昔のフォルダを受け取った人が対象になります。 スキル的にはjQuery(Bootstrap)なら何とか勢~(バックにも関心がある)SPA初心者勢を想定しています。 手順 1.本当に自前でやる必要があるか考える Webサービスが氾濫する現在、現在サイトにある機能を本当に自前で提供する必要があるか考えましょう。 日記 まぁ最有力はブログへの移行ですね。黒歴史を消す人も多いですが、逆に過去の日記みたいなもんで、残しておきたいと思う人もいるかと思います。ていうかホームページは放置してて日記にあたる部分だけ流石にブログに移行してる人も多いかと思いますね。 何らかの理由でブログに移行できない、不適切だと思う場合はスクレイピングして文章データをmdやらjsonに纏めて、今流行りのGatsbyあたりに手を出すのも良いのではないでしょうか。 イラスト これは現行のシェアとしてもシステム的にもpixivへ丸投げするのが一番妥当かと思います。 画像ギャラリー系のライブラリを入れて自前のサイトで見せることもできますが、pixivと二重管理になって放置する可能性が高いかと。 小説 これは難しい。投稿サイトは昔から山ほどありますが、なろうを始め色がついてたりするので……。(2~3年で閉鎖しないという意味で)安定してて、ジャンル問わずで一強みたいなのがあればいいんですが。 あと00年代初頭って「Web小説ならではリッチ表現を目指そう」的な流れもあって、小説本文中に挿絵画像ぶちこんだり、JSやフォントタグ弄りやってたりする小説もそこそこあるので、そこらへん守る必要がある(ギミックが前提)があったり、その系譜を現代の技術で更に進化させたいという気骨の方は自前も全然アリだと思います。 掲示板 これも難しい。 SNSの直接交流やハッシュタグ交流で代替できちゃってそうで完全には出来てないので、「アカウントを持たなくても書ける、個人管理のフォーラム」のニーズは確かにあるんですよ。 ただ当時でいうところのCGI(死語)がPerl/PHP+ただのログファイルで出来てたのに対し、現在はバックエンド系言語(Ruby/PHP等) + フレームワーク + DBが普通かつ、今時の設計だとバックエンドはAPIのみとなって、表示面はフロントエンドでやる必要があると敷居上がりまくってるんですよね。真っ向からやるにはバックエンドの勉強をガッツリしないときついかと。 OSSのフォーラムアプリも調べましたが、需要がニッチ化したのと、今だとバックエンドAPI+フロントエンドのセット提供になり、なおかつ密結合にならざるを得ないので、今一つ開発が盛り上がってない印象を受けました。現行問題なく動いてるのならそのまま+SNS交流で逃げてもいいのではという感触はありますね。 ゲーム系チャットアプリのイメージが強いですが、discordとかで丸投げできないかなーというのは考えたりしますが、使ったことがないので(ry チャット 掲示板と同じくdiscordに丸投げできないかな~(ry 2. WebスクレイピングしてHTMLから実データを取り出して整形する 昔はHTMLファイルの中に装飾データ(fontタグ)や実データを含めて全てが詰まっていたので、解析してオブジェクトの形に纏める(=スクレイピング)のは必須ですね。DOMを、tableタグを、ひたすら掘り続けるのだ……⛏ ゲーム攻略サイトとかデータ系サイトはここの工数を覚悟しといた方がいいです。抽出もさることながら、使い勝手が悪いとか色々データ整形したくなると思うので、延々とデータ整形することになります(体験談) ところでスクレイピングといえばPython (というかBeautifulSoup)がオススメとされていますが、「Webフロントエンド系の技術は仕方ないにせよ、Pythonまで手出すのはキツイ……」と思う方も多いかと思います。 そういう方は、そもそも自分のサイトであることを活かし、 ローカルの開発サーバー(手っ取り早いのはVSCodeの拡張機能のLiveServerとか)を用意 自サイトにJSのスクレイピングプログラムを仕込んでデータオブジェクトを作る 以下のJSでJSONファイルを生成してダウンロードさせる export const downloadJsonFile = (data: unknown, baseName: string): void => { const blob = new Blob([JSON.stringify(data)], { "type": "application/json" }) const fileName = `${baseName}.json` const url = URL.createObjectURL(blob) //aタグを生成し、クリックしたことにしてDLさせるというアプローチを取る //かなり無理くり感あるが現状これがベストプラクティスな模様。 const aTag = window.document.createElement("a") document.body.appendChild(aTag) aTag.download = fileName aTag.href = url aTag.click() aTag.remove() URL.revokeObjectURL(url) //生成したURLが保持されてしまうので解放する } こういう感じで対処しましょう。ちなみに自分はJSでファイルを生成→DLさせられるのを知らなくて、途中までconsole.logに吐き出し→エディタにコピペでせっせとJSONファイルを作ってました? 参考:JavaScriptでファイルダウンロード処理を実現する - Qiita 3.旧サイトとの連携を気にしつつ好きな技術で作り直す わざわざ作り直したいと思うぐらいですし、サイトの規模としてはそこそこ大きいですよね?となると、旧サイトと繋がりを意識しつつ徐々に入れ替えていく形を取る方が良いかと思います。 技術面に関してはお好きな技術で……としか言いようがありませんが、最近のトレンドから言うと大規模→React/小規模→Vue or Svelteという形になるのかなと思います。 また元が静的なウェブサイトという特性からリフォーム後も静的な特性が強いかと思われるので、SSGとの親和性が高いのかな~とも感じます。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

タイトル

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

タイトル

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

タイトル

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

【PHP】array_unique関数で配列の重複したデータを削除

array_unique関数 array_unique関数を使うことで、配列の重複したデータを削除することが出来ます。 array_unique.php $fruits = ['apple','lemon','strawberry','apple','orange','strawberry','lemomn']; $result = array_unique($fruits); var_dump($result); array(5) { [0]=> string(5) "apple" [1]=> string(5) "lemon" [2]=> string(10) "strawberry" [4]=> string(6) "orange" [6]=> string(6) "lemomn" } このように重複している値を削除することが出来ました!
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel コントローラをtinkerから実行する

tinkerからコントローラを実行できると便利なので、その方法をご紹介します。 環境 PHP: 8.0.10 Laravel: 8.58.0 モデル、コントローラを作る $ php artisan make:model Book $ php artisan make:controller BookController app/Models/Book.php app/Http/Controllers/BookController.php index: 引数なしのメソッドを実行する app/Http/Controllers/BookController.php <?php declare(strict_types=1); namespace App\Http\Controllers; use App\Models\Book; use Illuminate\Http\Request; final class BookController extends Controller { /** * @return array */ public function index(): array { return [ 'data' => [ 'id' => 1, 'name' => 'PHP Book', ] ]; } } だいぶ適当な関数ですが、これをtinkerから実行してみます。 $ php artisan tinker >>> $controller = app()->make(\App\Http\Controllers\BookController::class); => App\Http\Controllers\BookController {#3449} >>> app()->call([$controller, 'index']); => [ "data" => [ "id" => 1, "name" => "PHP Book", ], ] コントローラをtinkerから実行できました! store: Requestオブジェクトのあるメソッドを実行する app/Http/Controllers/BookController.php <?php declare(strict_types=1); namespace App\Http\Controllers; use App\Models\Book; use Illuminate\Http\Request; final class BookController extends Controller { /** * @param Request $request * @return array */ public function store(Request $request): array { return [ 'data' => $request->all(), ]; } } Request オブジェクトが必要な時の例です。 $ php artisan tinker >>> $params = ['name' => 'Laravel Book']; => [ "name" => "Laravel Book", ] >>> $request = \Illuminate\Http\Request::create('/books', 'POST', $params); => Illuminate\Http\Request {#3452 +attributes: Symfony\Component\HttpFoundation\ParameterBag {#3448}, +request: Symfony\Component\HttpFoundation\InputBag {#3450}, +query: Symfony\Component\HttpFoundation\InputBag {#3449}, +server: Symfony\Component\HttpFoundation\ServerBag {#3441}, +files: Symfony\Component\HttpFoundation\FileBag {#3440}, +cookies: Symfony\Component\HttpFoundation\InputBag {#3446}, +headers: Symfony\Component\HttpFoundation\HeaderBag {#3444}, } >>> $controller = app()->make(\App\Http\Controllers\BookController::class); => App\Http\Controllers\BookController {#3442} >>> app()->call([$controller, 'store'], ['request' => $request]); => [ "data" => [ "name" => "Laravel Book", ], ] show: Bookオブジェクトのあるメソッドを実行する app/Http/Controllers/BookController.php <?php declare(strict_types=1); namespace App\Http\Controllers; use App\Models\Book; use Illuminate\Http\Request; final class BookController extends Controller { /** * @param Book $book * @return array */ public function show(Book $book): array { return [ 'data' => [ 'id' => $book->id, 'name' => $book->name, ], ]; } } Book モデルのオブジェクトが必要な時の例です。 $ php artisan tinker >>> $book = \App\Models\Book::factory()->make(['id' => 1, 'name' => 'PHP Book', 'created_at' => now(), 'updated_at' => now()]); => App\Models\Book {#4379 id: 1, name: "PHP Book", created_at: "2021-09-01 00:00:00", updated_at: "2021-09-01 00:00:00", } >>> $controller = app()->make(\App\Http\Controllers\BookController::class); => App\Http\Controllers\BookController {#4384} >>> app()->call([$controller, 'show'], ['book' => $book]); => [ "data" => [ "id" => 1, "name" => "PHP Book", ], ] 今回はDB作ってないので、Book::factory() でBookインスタンスだけ作ってます。 DBがある場合は $book = \App\Models\Book::find(1); 等でBookインスタンス取得してください。 参考 https://mellowhost.com/blog/how-to-call-a-controller-method-from-tinker-laravel.html https://gist.github.com/nasirkhan/809eee36875dc7c1935bc4289be214c6
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Carbon 生成の罠

はじめに 何度か php の carbon を利用している際に気付かずに起こしていた事象を、備忘録として記載します。 null を入れて生成 ユーザーの入力等をカーボンに変換する際は、 new Carbon($input) Carbon::parse($input) とすることが多いと思いますが、この$inputが空文字、null、空配列、falseなどの場合、生成されるインスタンスの日時は実行時点の日時になります。 入力をCrbonに変換してDBに登録、といった実装を注意せずに行うと、  null等を入れて生成    ↓  実行時点での日付で登録 といったコンボがエラーが起きずに発生し、後で入力していないのに日付が入っているといった事態になります。 対策 is_null()を用いてnullかどうかを判定するのも良いですが、空文字、空配列、false の回避も考えると、empty()の方が広範な判定を行うことができます。 大まかな構文としては以下の通りです。 $datetime = empty($input) ? null : Carbon::parse($input);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

curl_execの使い方

とりあえず結果 curl_exec.php <?php $ch = curl_init(); $options = [ CURLOPT_CUSTOMREQUEST => 'GET', CURLOPT_URL => 'api url', CURLOPT_HTTPHEADER => ['X-API-Key: api key'], CURLOPT_RETURNTRANSFER => true, CURLOPT_TIMEOUT => 3 ]; curl_setopt_array($ch, $options); $response = curl_exec($ch); $statusCode = curl_getinfo($ch, CURLINFO_HTTP_CODE); $result = json_decode($response, true); curl_close($ch); var_dump($statusCode); var_dump($result); curl_execでapiを叩きたいとの話があったのでまとめました。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

504 Gateway timeout 解決方法 on AWS

504 Gateway timeout 解決方法 on AWS Webシステムで、バックエンドで少々長い時間が掛かる処理が終わるまで待つ必要があるケースがありますが、デフォルト設定だと、大体60秒程でタイムアウトとなり、「504 Gateway timeout」が発生するという事が多いです。 AWSで、ELB->Apache->PHPと言うよくある構成で、どの様に設定して行くと良いかをメモがてら残しておきます。 構成 クライアント(ブラウザ) -> ELB(ALB) -> WEB(Apache -> PHP) -> DB(RDS on MySQL) 今回、DBは割愛します。 タイムアウト調整 ユースケース次第ですがAWSのナレッジでは、KeepAliveTimeoutなどをロードバランサーのアイドルタイムアウトよりも長いキープアライブタイムアウトにするように推奨されています。 https://aws.amazon.com/jp/premiumsupport/knowledge-center/apache-backend-elb/ 例)無限にはできませんので、システム要件等で、程よいタイムアウト値を検討する必要があります。 クライアント(デフォルト:ブラウザ依存) < ELB(60) < WEB(Apache 120) < WEB(PHP 120) それぞれ設定すべき箇所 少々極端ですが、10分(600秒)タイムアウトさせたくないとします。 クライアント(ブラウザ) ※多分ここで調整することは無いと思います。 Chrome 調べましたが、Chromeでタイムアウト設定を変更することはできないようです タイムアウトが何秒なのかなどのドキュメントも見当たらない・・・ Firefox about:configから、「network.http.connection-timeout」を調整 IE レジストリで、 KeepAliveTimeout、ServerInfoTimeoutのDWORD値を調整 https://docs.microsoft.com/en-US/troubleshoot/browsers/change-keep-alive-time-out Safari SafariNoTimeoutをアプリとしてインストールすると可能とのこと ELB アイドルタイムアウト Apache /etc/httpd/conf.d/aws_elb.confを作成して設定 例)600秒なので、1.25倍して、750秒にしてみました。 /etc/httpd/conf.d/aws_elb.conf # クライアントヘッダータイムアウト # ロードバランサーでアイドル接続を適切に切断できるように、ロードバランサーに設定されたアイドルタイムアウトよりも大きな値に設定します。 # ロードバランサーに適切に通知せずに、バックエンドサーバーで接続を終了すると、504 エラーが表示されることがあります。 Timeout 750 # キープアライブ # CPU 使用率を削減し、応答時間を改善するには、キープアライブをオンにします。 # キープアライブをオンにすると、ロードバランサーで、HTTP リクエストの度に新しい TCP 接続を確立する必要がありません。 KeepAlive On # キープアライブオプションが有効になっている場合は、ロードバランサーのアイドルタイムアウトよりも長いキープアライブタイムアウトを選択します。 KeepAliveTimeout 750 # キープアライブリクエストの最大数 # このオプションでは、キープアライブがオンになった時に単一の TCP 接続で処理するリクエストの数を設定します。 # リソースの使用を最適化するために、キープアライブリクエストの最大数は 100 以上に設定します。 MaxKeepAliveRequests 100 # AcceptFilter # AcceptFilter はデフォルトで有効になっており、接続に TCP_DEFER_ACCEPT オプションを使用するよう Apache に指示します。 # この設定では、TCP ソケットが「ハーフオープン」状態になることがあります。 # この場合、ロードバランサーでは接続が確立されているが、バックエンドインスタンスでは接続が確立されていないことを前提とします。 # ハーフオープン接続は、性能が高くないロードバランサーで最も一般的です。この場合、使用前の接続に時間がかかります。 AcceptFilter http none # ELB access_log format LogFormat "%{X-Forwarded-For}i %h %l %u %t \"%r\" %>s %b %D \"%{Referer}i\" \"%{User-Agent}i\"" combined # Set over AWS ELB connection time out default 60s # 長時間にわたる少量ずつの読み込み/書き込み処理を悪用する攻撃 (Slowloris など) に対して接続を自動的に閉じる RequestReadTimeout header=750 PHP おなじみのphp.iniでmax_execution_timeの値で定義する方法 ただし、全体的にスクリプトが実行可能な秒数が伸びてしまうので注意が必要 /etc/php.ini ;;;;;;;;;;;;;;;;;;; ; Resource Limits ; ;;;;;;;;;;;;;;;;;;; ; Maximum execution time of each script, in seconds ; http://php.net/max-execution-time ; Note: This directive is hardcoded to 0 for the CLI SAPI max_execution_time = 60 処理中に、set_time_limit(int $seconds): bool で実行時間の最大値を制限する <?php set_time_limit(750); while ($i<=10) { echo "i=$i "; sleep(100); $i++; } ?>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

フレームワーク無しHTMLテーブルをBootstrapで再現する場合

過去に作ったフレームワーク無しのHTMLテーブルを、Bootstrap(5)で再現しようとすると、 過去、手抜き、つまりborder-bottom: noneなどで罫線を消してセル結合っぽくしている場合、 (HTML的にはダメですが、ループを回してDBを表示する場合めんどくさくてつい…) 融通がきかなくて困る場合があります(した)。 こういうテーブルです 手抜きをBootstrapで再現 HTML 罫線無しのテーブル(table-borderless)にして、個別にborderを設定する 同列の前行が違う値だったら、border-topを追加設定する <div class="table-responsive"> <table class="table table-borderless"> <thead class="text-center table-light"> <tr> <th scope="col" class="border-start border-top" nowrap>部名</th> <th scope="col" class="border-start border-top" nowrap>部長</th> <th scope="col" class="border-start border-top" nowrap>課名</th> <th scope="col" class="border-start border-top" nowrap>課長</th> <th scope="col" class="border-start border-top" nowrap>ユニット名</th> <th scope="col" class="border-start border-top" nowrap>ユニット<br>リーダー</th> <th scope="col" class="border-start border-end border-top" nowrap>メンバー</th> </tr> </thead> <tbody> <tr> <td class="border-start border-top" nowrap>何でも部</td> <td class="border-start border-top" nowrap>部長 太郎</td> <td class="border-start border-top" nowrap>課1</td> <td class="border-start border-top" nowrap>課長 太郎</td> <td class="border-start border-top" nowrap>ユニット1</td> <td class="border-start border-top" nowrap>ユニット 太郎</td> <td class="border-start border-end border-top" nowrap>メンバー 太郎</td> </tr> <tr> <td class="border-start" nowrap></td> <td class="border-start" nowrap></td> <td class="border-start" nowrap></td> <td class="border-start" nowrap></td> <td class="border-start" nowrap></td> <td class="border-start" nowrap></td> <td class="border-start border-end" nowrap>メンバー 次郎</td> </tr> <tr> <td class="border-start" nowrap></td> <td class="border-start" nowrap></td> <td class="border-start" nowrap></td> <td class="border-start" nowrap></td> <td class="border-start border-top" nowrap>ユニット2</td> <td class="border-start border-top" nowrap>ユニット 次郎</td> <td class="border-start border-end border-top" nowrap>メンバー 三郎</td> </tr> <tr> <td class="border-start" nowrap></td> <td class="border-start" nowrap></td> <td class="border-start border-bottom" nowrap></td> <td class="border-start border-bottom" nowrap></td> <td class="border-start border-bottom" nowrap></td> <td class="border-start border-bottom" nowrap></td> <td class="border-start border-end border-bottom" nowrap>メンバー 四郎</td> </tr> <tr> <td class="border-start" nowrap></td> <td class="border-start" nowrap></td> <td class="border-start border-top" nowrap>課2</td> <td class="border-start border-top" nowrap>課長 次郎</td> <td class="border-start border-top" nowrap>ユニット1</td> <td class="border-start border-top" nowrap>ユニット 三郎</td> <td class="border-start border-end border-top" nowrap>メンバー 五郎</td> </tr> <tr> <td class="border-start" nowrap></td> <td class="border-start" nowrap></td> <td class="border-start" nowrap></td> <td class="border-start" nowrap></td> <td class="border-start" nowrap></td> <td class="border-start" nowrap></td> <td class="border-start border-end" nowrap>メンバー 六郎</td> </tr> <tr> <td class="border-start" nowrap></td> <td class="border-start" nowrap></td> <td class="border-start" nowrap></td> <td class="border-start" nowrap></td> <td class="border-start border-top" nowrap>ユニット2</td> <td class="border-start border-top" nowrap>ユニット 四郎</td> <td class="border-start border-end border-top" nowrap>メンバー 七郎</td> </tr> <tr> <td class="border-start border-bottom" nowrap></td> <td class="border-start border-bottom" nowrap></td> <td class="border-start border-bottom" nowrap></td> <td class="border-start border-bottom" nowrap></td> <td class="border-start border-bottom" nowrap></td> <td class="border-start border-bottom" nowrap></td> <td class="border-start border-end border-bottom" nowrap>メンバー 八郎</td> </tr> </tbody> </table> </div><!-- .table-responsive --> PHP <?php $data[0] = array("何でも部", "部長 太郎", "課1", "課長 太郎", "ユニット1", "ユニット 太郎", "メンバー 太郎"); $data[1] = array("何でも部", "部長 太郎", "課1", "課長 太郎", "ユニット1", "ユニット 太郎", "メンバー 次郎"); $data[2] = array("何でも部", "部長 太郎", "課1", "課長 太郎", "ユニット2", "ユニット 次郎", "メンバー 三郎"); $data[3] = array("何でも部", "部長 太郎", "課1", "課長 太郎", "ユニット2", "ユニット 次郎", "メンバー 四郎"); $data[4] = array("何でも部", "部長 太郎", "課2", "課長 次郎", "ユニット1", "ユニット 三郎", "メンバー 五郎"); $data[5] = array("何でも部", "部長 太郎", "課2", "課長 次郎", "ユニット1", "ユニット 三郎", "メンバー 六郎"); $data[6] = array("何でも部", "部長 太郎", "課2", "課長 次郎", "ユニット2", "ユニット 四郎", "メンバー 七郎"); $data[7] = array("何でも部", "部長 太郎", "課2", "課長 次郎", "ユニット2", "ユニット 四郎", "メンバー 八郎"); ?> <div class="table-responsive"> <table class="table table-borderless"> <thead class="text-center table-light"> <tr> <th scope="col" class="border-start border-top" nowrap>部名</th> <th scope="col" class="border-start border-top" nowrap>部長</th> <th scope="col" class="border-start border-top" nowrap>課名</th> <th scope="col" class="border-start border-top" nowrap>課長</th> <th scope="col" class="border-start border-top" nowrap>ユニット名</th> <th scope="col" class="border-start border-top" nowrap>ユニット<br>リーダー</th> <th scope="col" class="border-start border-end border-top" nowrap>メンバー</th> </tr> </thead> <tbody> <?php $i = 0; while($i < count($data)){ echo " <tr>\n"; //先頭行 if ($i == 0) { echo " <td class=\"border-start border-top\" nowrap>{$data[$i]{0}}</td>\n"; echo " <td class=\"border-start border-top\" nowrap>{$data[$i]{1}}</td>\n"; echo " <td class=\"border-start border-top\" nowrap>{$data[$i]{2}}</td>\n"; echo " <td class=\"border-start border-top\" nowrap>{$data[$i]{3}}</td>\n"; echo " <td class=\"border-start border-top\" nowrap>{$data[$i]{4}}</td>\n"; echo " <td class=\"border-start border-top\" nowrap>{$data[$i]{5}}</td>\n"; echo " <td class=\"border-start border-end border-top\" nowrap>{$data[$i]{6}}</td>\n"; } else { //先頭行後 $j = 0; while($j <= 6){ //上罫線 $borderTop = " border-top"; //表示データ $val = $data[$i][$j]; //同列の前行と値が一致したら上罫線と値は表示しない if ($data[$i]{$j} == $data[$i - 1]{$j}) { $borderTop = ""; $val = ""; } //右罫線 //最終列のみ右罫線表示 $borderEnd = ""; if ($j == 6) { $borderEnd = " border-end"; } //下罫線 //最終行のみ下罫線表示 $borderBottom = ""; if ($i == count($data) - 1) { $borderBottom = " border-bottom"; } echo " <td class=\"border-start{$borderEnd}{$borderTop}{$borderBottom}\" nowrap>{$val}</td>\n"; $j++; } } echo " </tr>\n"; $i++; } ?> </tbody> </table> </div><!-- .table-responsive --> HTML的に正しいやり方 HTML 罫線有りのテーブル(table-bordered)にして、同じ値の場合はセルを結合する <div class="table-responsive"> <table class="table table-bordered"> <thead class="text-center table-light"> <tr> <th scope="col" nowrap>部名</th> <th scope="col" nowrap>部長</th> <th scope="col" nowrap>課名</th> <th scope="col" nowrap>課長</th> <th scope="col" nowrap>ユニット名</th> <th scope="col" nowrap>ユニット<br>リーダー</th> <th scope="col" nowrap>メンバー</th> </tr> </thead> <tbody> <tr> <td nowrap rowspan="8">何でも部</td> <td nowrap rowspan="8">部長 太郎</td> <td nowrap rowspan="4">課1</td> <td nowrap rowspan="4">課長 太郎</td> <td nowrap rowspan="2">ユニット1</td> <td nowrap rowspan="2">ユニット 太郎</td> <td nowrap>メンバー 太郎</td> </tr> <tr> <td nowrap>メンバー 次郎</td> </tr> <tr> <td nowrap rowspan="2">ユニット2</td> <td nowrap rowspan="2">ユニット 次郎</td> <td nowrap>メンバー 三郎</td> </tr> <tr> <td nowrap>メンバー 四郎</td> </tr> <tr> <td nowrap rowspan="7">課2</td> <td nowrap rowspan="7">課長 次郎</td> <td nowrap rowspan="2">ユニット1</td> <td nowrap rowspan="2">ユニット 三郎</td> <td nowrap>メンバー 五郎</td> </tr> <tr> <td nowrap>メンバー 六郎</td> </tr> <tr> <td nowrap rowspan="2">ユニット2</td> <td nowrap rowspan="2">ユニット 四郎</td> <td nowrap>メンバー 七郎</td> </tr> <tr> <td nowrap>メンバー 八郎</td> </tr> </tbody> </table> </div><!-- .table-responsive --> PHP 同列の前行と違う値だったら(同じ値だったら何も表示しない) 内部に別ループを回し、同列の次行と違う値になるまでループを回し、結合数(rowspan)をカウント rowspanに結合数を設定 <?php $data[0] = array("何でも部", "部長 太郎", "課1", "課長 太郎", "ユニット1", "ユニット 太郎", "メンバー 太郎"); $data[1] = array("何でも部", "部長 太郎", "課1", "課長 太郎", "ユニット1", "ユニット 太郎", "メンバー 次郎"); $data[2] = array("何でも部", "部長 太郎", "課1", "課長 太郎", "ユニット2", "ユニット 次郎", "メンバー 三郎"); $data[3] = array("何でも部", "部長 太郎", "課1", "課長 太郎", "ユニット2", "ユニット 次郎", "メンバー 四郎"); $data[4] = array("何でも部", "部長 太郎", "課2", "課長 次郎", "ユニット1", "ユニット 三郎", "メンバー 五郎"); $data[5] = array("何でも部", "部長 太郎", "課2", "課長 次郎", "ユニット1", "ユニット 三郎", "メンバー 六郎"); $data[6] = array("何でも部", "部長 太郎", "課2", "課長 次郎", "ユニット2", "ユニット 四郎", "メンバー 七郎"); $data[7] = array("何でも部", "部長 太郎", "課2", "課長 次郎", "ユニット2", "ユニット 四郎", "メンバー 八郎"); ?> <div class="table-responsive"> <table class="table table-bordered"> <thead class="text-center table-light"> <tr> <th scope="col" class="border-start border-top" nowrap>部名</th> <th scope="col" class="border-start border-top" nowrap>部長</th> <th scope="col" class="border-start border-top" nowrap>課名</th> <th scope="col" class="border-start border-top" nowrap>課長</th> <th scope="col" class="border-start border-top" nowrap>ユニット名</th> <th scope="col" class="border-start border-top" nowrap>ユニット<br>リーダー</th> <th scope="col" class="border-start border-end border-top" nowrap>メンバー</th> </tr> </thead> <tbody> <?php $i = 0; while($i < count($data)){ echo " <tr>\n"; //先頭行 if ($i == 0) { $j = 0; while($j <= 6){ //表示データ $val = $data[$i][$j]; //同列の次行と値が一致したら if ($data[$i]{$j} == $data[$i + 1]{$j}) { //結合数 $r = 1; //現行から開始 $n = $i; while($n < count($data) - 1){ if ($data[$i]{$j} == $data[$n + 1]{$j}) { $r++; } else { break; } $n++; } echo " <td rowspan=\"{$r}\" nowrap>{$val}</td>\n"; } else { //以外は値のみ表示 echo " <td nowrap>{$val}</td>\n"; } $j++; } } else { //先頭行後 $j = 0; while($j <= 6){ //表示データ $val = $data[$i][$j]; //同列の前行と値が一致しなかったら(一致したら何も表示しない) if ($data[$i]{$j} != $data[$i - 1]{$j}) { //結合数 $r = 1; //現行から開始 $n = $i; while($n < count($data) - 1){ if ($data[$i]{$j} == $data[$n + 1]{$j}) { $r++; } else { break; } $n++; } echo " <td rowspan=\"{$r}\" nowrap>{$val}</td>\n"; } $j++; } } echo " </tr>\n"; $i++; } ?> </tbody> </table> </div><!-- .table-responsive -->
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP】平日のみの日付リストを日数指定で取得

土日祝日を除いた平日の日付リストを日数指定で取得します。 祝日判定には以前作成した祝日取得クラスを利用してみました。 weekdays.php <?php require_once('holiday_class.php'); class Weekdays { private $holiday; private $startDate; public function __construct() { $this->holiday = new Holiday; $this->startDate = new DateTimeImmutable; } public function setStartDate($ymd = 'now') { $this->startDate = new DateTimeImmutable($ymd); } private function isHoliday($date) { [$y, $n, $j] = explode(',', $date->format('Y,n,j')); return isset($this->holiday->getHolidayOfYear($y)[$n][$j]); } public function getDateList($days = 1) { $days = max(1, $days); $currentDate = new DateTime; $currentDate->setTimestamp($this->startDate->getTimestamp()); $result = []; do { while(strpos('06', $currentDate->format('w')) !== false || $this->isHoliday($currentDate)) { $currentDate->modify('+1 day'); } $result[] = $currentDate->format('Y-m-d'); $currentDate->modify('+1 day'); } while(--$days > 0); return $result; } } example // example $weekdays = new Weekdays; $date_list = $weekdays->getDateList(7); print_r($date_list); /* Array ( [0] => 2021-09-17 [1] => 2021-09-21 [2] => 2021-09-22 [3] => 2021-09-24 [4] => 2021-09-27 [5] => 2021-09-28 [6] => 2021-09-29 ) */ foreach($date_list as $k => $v) { printf("%d: %s (%s)\n", $k, $v, ['日','月','火','水','木','金','土'][date('w', strtotime($v))] ); } /* 0: 2021-09-17 (金) 1: 2021-09-21 (火) 2: 2021-09-22 (水) 3: 2021-09-24 (金) 4: 2021-09-27 (月) 5: 2021-09-28 (火) 6: 2021-09-29 (水) */ $weekdays->setStartDate('2021-12-20'); $date_list = $weekdays->getDateList(20); print_r($date_list); /* Array ( [0] => 2021-12-20 [1] => 2021-12-21 [2] => 2021-12-22 [3] => 2021-12-23 [4] => 2021-12-24 [5] => 2021-12-27 [6] => 2021-12-28 [7] => 2021-12-29 [8] => 2021-12-30 [9] => 2021-12-31 [10] => 2022-01-03 [11] => 2022-01-04 [12] => 2022-01-05 [13] => 2022-01-06 [14] => 2022-01-07 [15] => 2022-01-11 [16] => 2022-01-12 [17] => 2022-01-13 [18] => 2022-01-14 [19] => 2022-01-17 ) */
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【EC-CUBE】XMLを出力したい【4系】

経緯 EC-CUBE4系の案件にてXMLを出力する仕様だったので対応。 手順 Controllerは普通に書きますが、アノテーションに「defaults={"_format"="xml"}」を定義します。 XMLフォーマットは画面同様twigにて記載します。 試しに指定したidのCustomerデータを表示するようにしてみます app/Customize/XmlController.php class XmlController extends AbstractController { /** * @Route("/xml/customer/{id}", name="xml_customer", defaults={"_format"="xml"}, requirements={"id" = "\d+"}) * @Template("Xml/customer.twig") */ public function customer(Request $request, Customer $Customer) { return ['Customer' => $Customer]; } } app/template/default/Xml/customer.twig <customer> <id>{{ Customer.id }}</id> <name>{{ Customer.name01 }} {{ Customer.name02 }}</name> <kana>{{ Customer.kana01 }} {{ Customer.kana02 }}</kana> </customer> 補足 標準出力はUTF-8です。 昨今は問題ないと思いますが、やっぱり環境的にShift-JIS(Win Server向け)で出力したいよねって言う場合もあると思いますが、その場合はControllerでmb_convert_encodingしてしまいます。 app/Customize/XmlController.php class XmlController extends AbstractController { /** * @Route("/xml/customer/{id}", name="xml_customer", defaults={"_format"="xml"}, requirements={"id" = "\d+"}) * @Template("Xml/customer.twig") */ public function customer(Request $request, Customer $Customer) { $res = $this->render('Xml/customer.twig', ['Customer' => $Customer]); $content = mb_convert_encoding($res->getContent(), 'SJIS-Win', mb_internal_encoding()); $response->setContent($content); return $response; } }
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む