20200911のPHPに関する記事は9件です。

PHP 、Laravel学習 1

これから学習したことをQiitaに投稿していきます。

非常に中途半端なところからのスタートになりますがご容赦下さい。

●Laravel学習

・MVCモデル
①ブラウザから送られてきた指令(リクエスト)をまずroutingが受け取る
②routingがどこにその指令を飛ばすべきかリクエストの種類を判別する
③controllerで受けとった場合、然るべきアクションを行う
④viewで受けとった場合そのままviewを返す(レスポンス)
⑤ブラウザに反映される

※多様なパターンがあり、一概に↑の順とは限らない

routing・・・リクエストを判別し、然るべき場所に信号を送る
controller・・・routingから送られてきたリクエストに大して然るべきアクションをする
view・・・表示するべきUI部分。
Model・・・データベースの前に立ち、操作しやすくするもの(?)

Model、view、controller
3つの要素の頭文字をとってMVCモデル

・データベース基礎
情報を保存しておくところ
Ex.ユーザーの名前、年齢、性別等

まず、データベースを操作する言語(データベース言語)について触れておきます
SQLといい、何種類かある
①MySQL
②PostgreSQL
③SQLite
存在するデータベースにより、どの言語が使われているかは異なるが
LaravelのModelはそれを全て統一して管理してくれるという便利機能付き

この言語を使い、データベースの雛形を作ったり、データを入力したりする

・CRUD処理

①Create・・・作成(タスクを作成したり、ツイートを作成したり)
②Read・・・読み込み(作成したタスクを読み込んだり、ツイートを読み込んだり)
③Update・・・更新(タスクを編集したり、追加する)
④Delete・・・削除(一度作ったデータを削除する)

WebアプリケーションではこのCRUD処理が必要不可欠である。

次回は実際に作りながら学んでいきたい

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

さくらVPSサーバーで作成したWebサービスのSSL化を行うに辺り、詰まった点

前提条件として

さくらVPSで環境構築が完了して、自分で作成したWebサービスの独自ドメインを取得しており
ドキュメントルートを設定して、ドメイン名(○○.com等)でhttp接続が完了しているという条件で
記述していきます。

作業環境

CentOS7
Apache2.4.6

Let's encryptで無料SSL証明書発行してSSL化

今回は無料でSSL証明書を発行したかったのでLet's encryptを使用しました。

詰まった箇所

https://weblabo.oscasierra.net/letsencrypt-2/

コチラの参考記事の内容を完璧に行ってもhttp接続からhttps接続に切り替わらない。

対策

参考記事に書かれている 
Apache 2.4 への設定が上手く反映されていない可能性を考える。

$apachectl configtest←このコマンドでssl.confの構文チェックを行う。

すると下記エラーメッセージが出る。

Syntax error on line XX of /path/to/ssl.conf:
SSLCertificateFile: file '/path/to/cert.pem' does not exist or is empty

上記エラーメッセージで検索しまくると

https://www.proto-star.com/2016/04/24/lets-encrypt-apache-%E3%81%A7%E3%81%A1%E3%82%83%E3%82%93%E3%81%A8%E8%A8%BC%E6%98%8E%E6%9B%B8%E3%81%AE%E7%94%9F%E6%88%90%E3%81%8C%E5%AE%8C%E4%BA%86%E3%81%97%E3%81%A6%E3%82%8B%E3%81%AE%E3%81%AB/

コチラの記事に巡り合えた。パーミッションの設定を変更してみると

$ apachectl configtest
Syntax OK

Apache 2.4 への設定は上手くいったことを確認して再度ブラウザを確認すると今度は接続タイムアウトのエラーが。。

色々調べているとファイアウォールかApacheのエラーが原因ぽかったので

ファイヤーウォールの確認
$ firewall-cmd --list-all --permanent
apacheの確認
$ systemctl status httpd

上記コマンドを叩いてみるとファイアウォールの方は問題なさそうなのですが
apacheの方は長文の英文メッセージの中にfailedという文字が。。

はい、アパッチが原因ですね。

アパッチのエラーログを確認するとssl.conf内のポート番号443が重複しているというようなエラーメッセージが出力されている。

glepコマンドで443で検索をかけると、バックアップ用にコピーしていた

ssl.old.conf
ssl.oldest.conf

上記ファイルが本丸のssl.confと競合していた。。

なのでこれらのファイルを削除して再度アパッチを起動してブラウザを確認すると

接続タイムアウトのエラーが解決されて、https接続もしっかり出来ていました。

バックアップファイルの取り方に問題があったようでOSは拡張子で判断するのでバックアップファイルを取るなら下記のようにするのが正解のようです。

ssl.conf.bak
ssl.conf.old

拡張子は完全に盲点でした。。
今回のような訳の分からないエラーが出た時は、今思うと当たり前ですがエラーログをしっかり見てから、解決に向けて行動をした方が良いですね。

ていうかプログラミングでエラーにぶつかった時は基本的にエラーログを見るのは当たり前なのですが、環境構築に対する知識が乏しく、アパッチにエラーログがあるという概念すらなかったです。

とはいえ、今回のエラーで環境構築やネットワーク関連の知識がある程度付いたのでエラーに巡り合えて良かったと
ポジティブな結果として終わらそうと思います笑

長文失礼致しました!

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

LaravelでSwift_TransportExceptionが発生した時の対処法(Gmail編)

問題

  • Laravelでメール送信しようとしたらSwift_TransportExceptionというエラーが発生した。
  • Authenticator LOGIN returned Expected response code 235 but got code "534"が発生した。

自分は上記の両方を認証機能のパスワード再発行の際に発生した。
それらを解決できたので、その方法を記載する。

解決策

今回はGmailを利用した解決策を書いていく。

.env

まずはenvファイルの設定を確かめる。

MAIL_DRIVER=smtp
MAIL_HOST=smtp.gmail.com
MAIL_PORT=465
MAIL_ENCRYPTION=ssl
MAIL_FROM_ADDRESS=laravel@admin.com(適当なメールアドレス)
MAIL_FROM_NAME=Admin(適当な名前)
MAIL_USERNAME=(自分が利用しているGmailアドレス)
MAIL_PASSWORD=
MAIL_PRETEND=false

MAIL_PASSWORDの所に何も記入されていないが後で記入する。

config/mail.php

config/mail.phpを次のように書き換える。
既に記入されていたコードはコメントアウトなどで保存。

config/mail.php
// Mail Driver
'driver' => env('MAIL_DRIVER', 'smtp'),

// SMTP Host Address
'host' => env('MAIL_HOST', 'smtp.mailgun.org'),

// SMTP Host Port
'port' => env('MAIL_PORT', 587),

// Global "From" Address
'from' => [
    'address' => env('MAIL_FROM_ADDRESS', null),
    'name' => env('MAIL_FROM_NAME', null)
],

// E-Mail Encryption Protocol
'encryption' => env('MAIL_ENCRYPTION', null),

// SMTP Server Username
'username' => env('MAIL_USERNAME', null),

// SMTP Server Password
'password' => env('MAIL_PASSWORD', null),

// Sendmail System Path
'sendmail' => '/usr/sbin/sendmail -bs',

// Mail "Pretend"
'pretend' => env('MAIL_PRETEND', false),

Googleのセキュリティ設定

下記のサイトを参考にGoogleアカウントの2段階認証、またはアプリパスワードの設定を行う。
【laravel】メール(gmail)がエラーで送信出来ない問題 | 旅行好き・WEBエンジニアのブログ

自分は2段階認証ではエラーが解消しなかったが、アプリパスワードの設定によって解消できた。

アプリパスワードが発行されたら、.envMAIL_PASSWORD=に入力する。

キャッシュの削除

今のままだとLaravelの変更前の設定ファイルの記録などが残っているため、$ php artisan config:cacheをターミナルで実行しそれらを削除する。

以上の作業が終わったら、自分が操作したいメール送信機能を試してみる。

参考資料

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

Laravelの配列操作ラッパー、Collectionを単品で使用してみる

概要

Laravelのcollectionが便利なので単品で使いたい
コレクション -Laravelドキュメント

install

% composer require illuminate/support

code

sample.php

<?php
require_once "vendor/autoload.php";

$array = ['key' => 'value'];
$collection = collect($array);
var_dump($collection);

結果

% php sample.php 
object(Illuminate\Support\Collection)#3 (1) {
  ["items":protected]=>
  array(1) {
    ["key"]=>
    string(5) "value"
  }
}

できた!

参考

おまけ

docker-compose.yml

version: '3'
services:
  php:
    container_name: php-collection
    build:
      context: .
      dockerfile: docker/php/Dockerfile
    volumes:
      - ./php:/var/www
    tty: true
    working_dir: /var/www
    env_file:
      - ./.env

Dockerfile

FROM php:7.4

COPY --from=composer:latest /usr/bin/composer /usr/bin/composer

RUN cp /usr/share/zoneinfo/Asia/Tokyo /etc/localtime \
    && apt-get update \
    && apt-get install -y zip unzip

build & 起動 & 実行

docker-compose build php
docker-compose up -d
docker exec -it php-collection /bin/bash

composer require illuminate/support
vi ./sample.php
php ./sample.php
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【PHP】TrueとFalseを出力する

<LABEL>-<MESSAGE>

やりたいこと

trueはtrue、falseはfalseと出力したい。

うまくいかなかった方法

配列をtrueとfalseで初期化し、値を出力した。

$tf = array(true,false,true,false);

for($i = 0;$i < 4;$i++){
    print $tf[$i]."<br>";
}

結果

trueは1、falseは""と出力される

1

1

うまくいった方法

出力の際にvar_exportを使った。

$tf = array(true,false,true,false);

for($i = 0;$i < 4;$i++){
    print var_export($tf[$i])."<br>";
}

結果

trueはtrue、falseはfalseと出力される。

true
false
true
false

まとめ

PHPはtrueとfalseがそのまま出力されないため、var_exportが必要。

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

Adminerでoracleに繋げる

Adminerとは

AdminerはPHPで動作するWebSQLクライアントです。
https://www.adminer.org/

同じ物に言わずとしれたphpMyAdminですが使えるのはMysqlだけ。
一方AdminerではmysqlのほかにPostgreSQL、SQLite、MS SQL、Oracleなど幅広く扱えます。

oracle

本題です。
そんななかoracleに繋げる時だけログインフォームに癖がありこれが毎度忘れるので記事にします。

image.png

これはDockerでoracleDBをインストールした場合のデフォ情報の場合です。

Serverにはホスト名(TNS名)/サービス名の両方を/で仕切り、入力する必要があります。
User名はログインユーザ
Databaseはスキーマ名となります。

大文字小文字が区別されるので注意です。

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

PHP(Imagick)でイメージをマスクして切り取る

完成形

test.png

画像の左右を斜めに切り取っています。

mask223.png

やりたいこととしては、上記の画像の赤枠で囲っている、2つの画像を合わせてその合わさっている場所を切り抜きたい。

元画像とマスク用画像の用意

元画像
Zoe_0.jpg

マスク用の画像(同じサイズで左右の斜めを透過してあります。)
mask2.png

 実装

    //元画像をURLから呼び出し
    $thumbnail = file_get_contents("http://ddragon.leagueoflegends.com/cdn/img/champion/loading/Zoe_0.jpg");
    $image = new Imagick();
    $image->readImageBlob($thumbnail);
    //アルファチャネルの設定で、黒い部分を透明にする。
    $image->setImageAlphaChannel(Imagick::ALPHACHANNEL_RESET);
    //マスク用の画像を取得
    $mask = new Imagick(storage_path("mask.png"));
    //元画像を重ね合わせてマスクする
    //COMPOSITE_DSTOUTにすると、重なっている部分が切り抜かれる
    $image->compositeImage($mask, Imagick::COMPOSITE_DSTIN, 0, 0);
    //保存
    $image->writeImage(storage_path("test.png"));

以上で簡単な実装です。

さらにこれに画像を重ね合わせたり、文字を入れたりするとOGP的な画像の動的生成などができるかと思います。

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

IBM i oci8.so でセグメンテーション障害(core dumped)

IBMiとOracleで嵌り事象に遭遇したので、備忘録として。

突然のセグメンテーション障害(core dumped)

IBMi 環境下のPHPoci8.soを使用して、ユーザーのPHPアプリケーションテストをしたところ、ある日突然なんのエラーメッセージも出力されず「セグメンテーション障害(core dumped)」となり、PHPアプリケーションが落ちてしまう様になった。エラー時に出力された、スプールは以下の通り。

 MCH6801    エスケープ            40   20/09/07  20:04:46.275123  QP2USER2     QSYS        *STMT    QP2USER2    QSYS        *STMT
                                      送信元モジュール. . . . . :   QP2API
                                      送信元プロシージャー. . . :   runpase_common__FiPvT2
                                      ステートメント. . . . . . :   5
                                      送信先モジュール. . . . . :   QP2API
                                      送信先プロシージャー. . . :   runpase_common__FiPvT2
                                      ステートメント. . . . . . :   5
                                      メッセージ. . :   オブジェクトQPADEV0001USHIDAY   505789のオフセット
                                        X'0000000000000018'のオブジェクト・ドメインまたは記憶域保護エラー。
                                      原因--プログラムは,ブロック化された命令を使用しようとしたか,システム・ド
                                        メイン・オブジェクトをアクセスしようとしたか,あるいは保護されたページを間
                                        違って使用しようとしました。違反タイプは4です。違反タイプは以下のタイプ
                                        のエラーを示します。1-オブジェクト・ドメイン違反。2-テスト・ポインター
                                        ・ターゲット・アドレス可能度(TESTPTA)違反。3-読み取り保護エラー。
                                        4-書き込み保護エラー。5-実行保護エラー。空間クラスはX'08'です。空間
                                        クラスは,記憶域保護エラーまたは空間ポインターのTESTPTA違反の空間のタイ
                                        プを示します。00- 1次関連空間(空間オブジェクトを含む)。01- 2次関連空
                                        間。02-自動記憶域用の暗黙の処理空間。03-静的記憶域用の暗黙的処理空間。
                                        04-活動化グループに基づくヒープ記憶域の暗黙の処理空間。05-定数空間。
                                        06-ハンドルに基づくヒープ記憶域用の空間。07-テラスペース・オフセット
                                        X'0000000000000018'。08- I5/OS PASEメモリー・アドレス
                                        X'0000000000000018'のテラスペース。X'80000000000000000000040050000018'は
                                        ,保護エラーまたは空間ポインターのTESTPTA違反の記憶域へのポインターです
                                        。一部の違反は,低システム機密保護レベルで抑制されている場合があります。
 CPFB9C6    エスケープ            40   20/09/07  20:04:46.438840  QP2FORK      QSYS        *STMT    QP0ZPCPN    QSYS        *STMT
                                      送信元モジュール. . . . . :   QP2FORK
                                      送信元プロシージャー. . . :   send_escape__FPcPvUi
                                      ステートメント. . . . . . :   11
                                      送信先モジュール. . . . . :   QP0ZPCPN
                                      送信先プロシージャー. . . :   Qp0zNewProcess
                                      ステートメント. . . . . . :   278
                                      メッセージ. . :   PASE FOR Iが終了しました。シグナル11,エラー・コード
  5770SS1 V7R2M0 140418                           ジョブ・ログ                     CSC2015   20/09/07  20:04:46 JST ページ    2
   ジョブ名 . . . . . . . . . :   QPADEV0001      ユーザー. . . . :   USHIDAY      番号 . . . . . . . . . . . :   505789
   ジョブ記述 . . . . . . . . :   USHIDAYJD       ライブラリー. . :   USHIDA
 MSGID     タイプ                 SEV 日付    時刻            FROM PGM     ライブラリー     INST     TO PGM      LIBRARY     INST
                                        1。
                                      原因--PASE FOR Iプログラムは,PASE FOR Iシグナル11のため終了しました
                                        。エラー・コード1は,現行ディレクトリーにコア・ファイルが書き込まれたこ
                                        とを示しています。このシグナルは,ジョブ・ログに表示される例外メッセージに
                                        対して作成されている可能性があります。回復手順--エラーを訂正して,要求
                                        を再試行してください。エラーの詳細説明--コア・ファイルが書き込まれてい
                                        る場合には,PASE FOR I 'DBX'コマンドでそれを調べてください。PASE FOR
                                        Iコマンドは,対話式ジョブでプログラムQP2TERMを呼び出すことにより表示され
                                        るコマンド行で入力できます。
 CPF24A3    エスケープ            40   20/09/07  20:04:46.439263  QMHSNDPM     QSYS        0C79     QLEAWI      QSYS        *STMT
                                      送信先モジュール. . . . . :   QLEDEH
                                      送信先プロシージャー. . . :   Q LE leDefaultEh2
                                      ステートメント. . . . . . :   175
                                      メッセージ. . :   呼び出しスタックのカウンター・パラメーターの値が正しくな
                                        い。
                                      原因--呼び出しスタックのカウンター・パラメーターに指定した値3が正しくあ
                                        りません。この値はAPIのパラメーター番号7に指定されました。回復手順-
                                        -呼び出しスタックのカウンター・パラメーターの値を訂正して要求を再試行して
                                        ください。この値は0以上でなければなりませんが,呼び出しスタックの項目数
                                        より大きくすることはできません。
 CEE9901    診断                  30   20/09/07  20:04:46.439299  QLEAWI       QSYS        *STMT    QP0ZPCP2    QSYS        *STMT
                                      送信元モジュール. . . . . :   QLETOOL
                                      送信元プロシージャー. . . :   Q LE CPF24A3_handler
                                      ステートメント. . . . . . :   9
                                      送信先モジュール. . . . . :   QP0ZPCP2
                                      送信先プロシージャー. . . :   _CXX_PEP__Fv
                                      ステートメント. . . . . . :   *N
                                      メッセージ. . :   アプリケーション・エラー。CPFB9C6は,QP0ZPCPNによっ
                                        てステートメント0000000278命令X'0000'で監視されていません。
                                      原因--例外が発生して処理されなかったので,アプリケーションは異常終了しまし
                                        た。未処理例外が送られるプログラムの名前はQP0ZPCPN QP0ZPCPN
                                        Qp0zNewProcessです。プログラムは,このメッセージが送られた時に高水準言語ス
                                        テートメント番号0000000278で停止されました。複数のステートメント番号が表
                                        示された場合には,プログラムは最適化されたILEプログラムです。最適化によ
                                        って単一ステートメント番号を判別することはできません。*Nが値として表示さ
                                        れた場合には,実際の値が使用できなかったことを意味します。回復手順--前
                                        にリストされた低レベル・メッセージを参照して,例外の原因を突き止めてくださ
                                        い。エラーを訂正してから,要求を再試行してください。
 CPC1219    完了                  50   20/09/07  20:04:46.439427  QWTPITP2     QSYS        0645     *EXT                    *N
                                      メッセージ. . :   このジョブは異常終了した。
                                      原因--このジョブが異常終了する原因となるエラーが起こりました。回復手順-
                                        -このジョブのジョブ・ログで,以前にリストされているメッセージを参照してく
                                        ださい。エラーを訂正して,要求を再試行してください。

結果的には、以前ユーザーは、Oracle 11gを使用していたのだが、今回から12cに変更されており、12cはユーザーに紐付く省略のDefaultプロファイルのパスワード期限が、180日だった事が原因でした。

事象のまとめ

今回の事象をまとめると以下の通り。

  • PHP on IBMi アプリケーションで、Oracle DBに接続。
  • 接続時には、セグメンテーション障害(core dumped)となり、実行カレントディレクトリにcoreのメモリダンプが吐き出されて異常終了となる。
  • Zend Server,コミュニティ版PHPどちらでも同様の現象となる。
  • 開発用Windowsで同様の処理をしても、正常に処理される。
  • IBMiからJava(JDBC)経由のアプリケーションでは、正常に処理される。
  • 旧Oracle 11gに接続先を向けると、正常に処理される。(この辺りで、ようやく12c固有の問題と判断が付きました)
  • IBMi上のSQLPlusでは、正常にログイン出来る。(ムムッ、なにやら不穏なワーニングORA-28002: the password will expire within 7 daysが...)
./sqlplus user/pwd@hostname:1521/database

SQL*Plus: Release 10.2.0.5.0 - Production on Mon Sep 7 21:49:09 2020
Copyright (c) 1982, 2010, Oracle.  All Rights Reserved.
ERROR:
ORA-28002: the password will expire within 7 days

どうも原因は、これのようで、IBMiのoci8.soまたはOracle Instant Clientの何れかが、このワーニングをハンドリング出来ていないのかな?通常なら、7日間の猶予があるようで、それでlocalやJavaは問題が表面化せず動作しているのかもしれません。

解決方法

デフォルトプロファイルのパスワード期限を無期限にするか、対象のプロファイルのパスワードを無期限にします。本来は、デフォルト変えてまうより、アプリケーション接続ユーザー様のプロファイルにするべきでしょうね。

  1. プロファイルの期限を設定
  2. アカウントロックを解除/パスワード再設定
# SQLplusで接続する
./sqlplus user/pwd@hostname:1521/database

# 無期限設定
alter profile DEFAULT limit PASSWORD_LIFE_TIME unlimited;
alter profile プロファイル名 limit PASSWORD_LIFE_TIME unlimited;

# 設定確認
SELECT * FROM dba_profiles WHERE PROFILE='DEFAULT' AND RESOURCE_NAME='PASSWORD_LIFE_TIME';

ROFILE
--------------------------------------------------------------------------------
RESOURCE_NAME                    RESOURCE
-------------------------------- --------
LIMIT
--------------------------------------------------------------------------------
COM INH IMP
--- --- ---
DEFAULT
PASSWORD_LIFE_TIME               PASSWORD
UNLIMITED
NO  NO  NO

Oracleのプロではないので、バージョン変わる時に流儀が変わっていると、嵌ることがよくあります。
因みに、明示的にユーザーをロックしたり、パスワードをExpireさせた時は、oci8.soから「~Loked~」など、メッセージが返され、Coredumped で落ちる事はないので、自然と180日で切れて、猶予期間が存在する時だけ起こる事象かもしれません。

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

sprintf()でSQL文を生成する際、%は%でエスケープできる



何を言っているのかわからねーと思うが、ありのままを話すぜ

2020/09/12 追記
コメントにてSQLインジェクションの原因となる脆弱性をご指摘いただきました。
本記事はsprinf()でSQLクエリを作成する事を推奨するものではないとご理解をお願いします。
@tadsan様 ありがとうございます。

はじめに

現在私はPHP+MySQLでフルスクラッチ開発をしている会社で働いているのですが、
まだ、入社して1ヶ月ほどなので既存のコードを読むことがほとんどです。

弊社ではphpファイルの中でSQL文を生成する際に
sprintf()を使用して、フォーマットを整えるようにしています。
(これがスタンダードなのかは不明)

その中で、いまいちよくわからない記述を調べていくうちに
興味深いルールに出会いましたので、忘れないようQiita残しておきます。

sprintf()でSQLの曖昧検索クエリを作る時

$freeword = 'qiita';

$sql = sprintf('SELECT * FROM title LIKE "%%%s%%"', $freeword);

このコードはsprintf()の第二引数 $freeword が、第一引数内の "%%%s%%" の部分に
置き換わってフォーマットされるのですがその際に気をつけたいルールがあります。

まず真ん中部分の「%s」は変数の値で今回の例ではqiitaに変換されます。
なので、この時点では「%%qiita%%」になる。

この段階で、筆者は
「無駄に%の数多くね?」
と、勘違いしていましたが

そもそもsprintf()で%という記号はそのまま文字として認識されないので
エスケープして文字とする必要があります。

そこで%をエスケープするための記号が%なのです。

つまりは

残った「%」のうち、後ろの%は、それぞれ手前の 「%」でエスケープされるので、結果としてただの「%」と言う「文字列」になります。

① %→「%」qiita %→「%」

② 結果「%qiita%」が残る

③ これがSQLのLIKE文に残ることで、結果として、
$sql = 'SELECT * FROM title LIKE %qiita%';
と言うSQL文の完成。

わかりやすい参考記事

下記ブログ記事の解説が初心者にも大変わかりやすかったので
記事作成の大部分に引用させていただきました。

・はらちゃんのブログ

ありがとうございます。

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