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

【PHP】バリデーション(半角英字・郵便番号・メールアドレス)

プログラミング初学者がアウトプットのため気まぐれ更新。
アドバイス等あればご教示頂きたく、よろしくお願い致します。

よく使うバリデーションをキロクしておきます。

半角英字

ユーザー名の登録などで使用する。
{ }のなかに数字をいれることで、文字数制限もできる。

validation.php
// 半角英字であるかチェック
$pattern ='/^[a-zA-Z]+$/';
// 8文字以内の半角英数字であるかチェック
$pattern ='/^[a-zA-Z0-9]{8}+$/';

郵便番号

validation.php
// 郵便番号であるかチェック
$pattern ='/[0-9]{3}-[0-9]{4}/';

メールアドレス

validation.php
// メールアドレスであるかチェック
$pattern ='/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/iD';

お問い合わせフォームでよく使うバリデーションをまとめました。
ありがとうございます。

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

【PHP】正規表現(半角英字・郵便番号・メールアドレス)

プログラミング初学者がアウトプットのため気まぐれ更新。
アドバイス等あればご教示頂きたく、よろしくお願い致します。

今回は、よく使う正規表現をキロクしておきます。

半角英字

ユーザー名の登録などで使用する。
{ }のなかに数字をいれることで、文字数制限もできる。

validation.php
// 半角英字であるかチェック
$pattern ='/^[a-zA-Z]+$/';
// 8文字以内の半角英数字であるかチェック
$pattern ='/^[a-zA-Z0-9]{8}+$/';

郵便番号

validation.php
// 郵便番号であるかチェック
$pattern ='/[0-9]{3}-[0-9]{4}/';

メールアドレス

validation.php
// メールアドレスであるかチェック
$pattern ='/^([a-z0-9\+_\-]+)(\.[a-z0-9\+_\-]+)*@([a-z0-9\-]+\.)+[a-z]{2,6}$/iD';

お問い合わせフォームでよく使う正規表現をまとめました。
ありがとうございます。

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

PHPでAWS S3 の大きいファイルの読込

やりたいこと

  • amazon s3 から大きめのファイルをダウンロードしたい
  • いちどに取得しよとすると大変そうなので少しずつ取得したい。
  • PHP で取得を行う

接続情報を準備する

define('S3', [  
        'KEY'   => AWSのS3のKEYを設定する,
        'PASS'  => AWSのS3のパスワードを設定する,
        'DIR'   => AWSのS3のディレクトリを設定する(s3://<bucket>[/<key-or-prefix>]))
]);

接続を行う

  • AWS SDK for PHP を使用して接続する
  • Amazon S3 ストリームラッパー を使用して接続操作を行う
require_once 'aws/vendor/autoload.php';

// S3 接続を行う
$s3 = S3Client::factory([
    'credentials' => [
        'key'       => S3['KEY'],
        'secret'    => S3['PASS'],
        ],
        'region' => 'ap-northeast-1',
    'version' => 'latest',
]);
$s3->registerStreamWrapper();
  • 関数は registerStreamWrappe を使用する
  • registerStreamWrapper を使用すると、ファイルの操作と同じく S3 にアップされているファイルを操作できる。

操作を行う

  • たとえば、指定しファイルがあるか確認を行う
    $readFileName = S3['DIR'].'/確認したいファイル名.XX';
    if(file_exists($readFileName)) {
        echo 'ファイルあり';
    }
  • たとえば、freadを使用して読み込みを行う
    $readFileName = S3['DIR'].'/読み込みたいファイル名.XX';
    $fp = fopen($readFileName, "r");
    while(!feof($fp)) {
        $file = fread($fp, 4096);
    }
    close($fp);
  • 上記のことからわかるように、接続後一般的なファイル操作で S3 のファイルを操作できる。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel シンボリックリンクが切れた時の復旧方法

Laravel のStorage を使っていて、シンボリックリンクが切れてファイルの読み込みができなくなる時があります。

その時の復旧方法を備忘録的に残します。

シンボリックリンクの設定

php artisan storage:link

これでシンボリックリンクの設定ができます。

Storage フォルダがroot直下にでき、/public 直下からリンクが張られます。

それでうまくいっていたはずが、色々やるうちに変わったり外れてしまった場合の対処法です。

シンボリックリンクの確認

ローカルの場合、仮想環境のサーバにログインします。

プロジェクトのフォルダまで移動し、ls -la でシンボリックリンクを確認します。

vagrant@homestead:~/code/project$ cd public
vagrant@homestead:~/code/project/public$ ls -la
total 24
drwxr-xr-x 1 vagrant vagrant  384 Jul  4 02:52 .
drwxr-xr-x 1 vagrant vagrant  960 Jun 28 07:37 ..
drwxr-xr-x 1 vagrant vagrant   96 Jun 16 11:26 css
-rw-r--r-- 1 vagrant vagrant 6148 May 15 06:23 .DS_Store
-rw-r--r-- 1 vagrant vagrant    0 Apr 10 07:56 favicon.ico
-rw-r--r-- 1 vagrant vagrant  603 Apr 10 07:56 .htaccess
-rw-r--r-- 1 vagrant vagrant 1823 Apr 10 07:56 index.php
drwxr-xr-x 1 vagrant vagrant   96 Jun 16 11:26 js
-rw-r--r-- 1 vagrant vagrant   71 Jun 28 07:38 mix-manifest.json
-rw-r--r-- 1 vagrant vagrant   24 Apr 10 07:56 robots.txt
lrwxr-xr-x 1 vagrant vagrant   45 Jul  4 02:52 storage -> /User/hogehoge/code/project/storage/app/public/
drwxr-xr-x 1 vagrant vagrant  128 May 15 08:02 voice

仮想環境なのに /User/hogehoge/code/project/storage/app/public/ みたいなパスになっていたら間違いです。

シンボリックリンクを削除する

リンクが間違っていたら、unlink でリンクを削除します。

vagrant@homestead:~/code/project/public$ unlink storage

正しいパスでシンボリックリンクを設定する

シンボリックリンクの設定は ln -s [正しいパス] [storage] です。

正しいパスは、$pwd でプロジェクトrootのパスを確認し、/project/storage/app/public/ を設定。

vagrant@homestead:~/code/project/public$ ln -s /home/vagrant/code/project/storage/app/public/ storage

ついでに: 本番環境でシンボリックリンクが繋がらないとき

単純に繋がっていないだけのことが多いので、サーバにログインして、storage:link しましょう。

php artisan storage:link

参考

https://qiita.com/YasuhaF/items/9a897e83afe1819d97af

https://www.wakuwakubank.com/posts/342-linux-ln-unlink/

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

PHP入門 - お問い合わせフォームを作ろう (1)

php.png

PHPを持っていない方は事前にインストールしておいてください。

フォーム画面の作成

任意のディレクトリにindex.phpを作成します。

index.php
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>お問合せフォーム</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
    <div class="container">
        <form action="" method="POST">
            <h4 class="py-4 text-center">お問い合わせ</h4>
            <div class="form-group">
                <div class="row justify-content-center">
                    <div class="col-md-8 col-offset-2">
                        <label for="inputName">お名前(必須)</label>
                    </div>
                    <div class="col-md-8 col-offset-2">
                        <input type="text" name="name" id="inputName" class="form-control rounded-0" required autofocus>
                        <p class="error_msg text-danger">※お名前をご記入下さい</p>
                    </div>
                </div>
            </div>
            <div class="form-group">
                <div class="row justify-content-center">
                    <div class="col-md-8 col-offset-2">
                        <label for="inputEmail">メールアドレス(必須)</label>
                    </div>
                    <div class="col-md-8 col-offset-2">
                        <input type="email" name="email" id="inputEmail" class="form-control rounded-0" required>
                        <p class="error_msg text-danger">※メールアドレスをご記入下さい</p>
                    </div>
                </div>
            </div>
            <div class="form-group">
                <div class="row justify-content-center">
                    <div class="col-md-8 col-offset-2">
                        <label for="inputContent">お問い合わせ内容(必須)</label>
                    </div>
                    <div class="col-md-8 col-offset-2">
                        <textarea name="contact" id="inputContent" rows="10" class="form-control rounded-0" required></textarea>
                        <p class="error_msg text-danger">※お問い合わせ内容をご記入下さい</p>
                    </div>
                </div>
            </div>
            <div class="row justify-content-center">
                <div class="col-md-8 col-offset-2">
                    <button type="submit" class="btn btn-primary w-100 rounded-0">確認画面へ</button>
                </div>
            </div>
        </form>
    </div>
</body>
</html>

ブラウザで確認すると、下の画面のようになっているのがわかります。

img1.png

入力チェック

サーバ側で入力チェックをするために、novalidateを追加します。

index.php
<form action="" method="POST" novalidate> // 追記

次に<!DOCTYPE>の上にPHPのコードを書いていきます。

index.php
<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $post = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);

    if ($post['name'] === '') {
        $error['name'] = 'blank';
    }
}
?>

名前が未入力のとき、変数名$errorに'blank'という値が入るようにします。
そして、名前入力欄に下記のコードを追加します。

index.php
<input type="text" name="name" id="inputName" class="form-control rounded-0" required autofocus>
// ここから
<?php if ($error['name'] === 'blank'): ?>
    <p class="error_msg text-danger">※お名前をご記入下さい</p>
<?php endif; ?>
// ここまで

ブラウザを更新します。すると、

img2.png

名前入力欄の下に表示されていたエラーメッセージが消えました。
空欄のまま「確認画面へ」ボタンを押してみてください。「※お名前をご記入ください」というエラーメッセージが表示されるはずです。
これで名前の入力チェックは完了です。

入力していた文字をそのまま残す

今の状態で「確認画面へ」ボタンを押すと、エラー時に入力していた文字が消えてしまいます。そこで、value属性を追加します。

index.php
<input type="text" name="name" id="inputName" class="form-control rounded-0" value="<?php echo htmlspecialchars($post['name']); ?>" required autofocus>

これでエラーになっても直前に入力していた文字が消えずに残るようになりました。

この調子で、メールアドレスとお問い合わせ内容を編集していきます。

index.phpの内容は下記の通りになります。

index.php
<?php
$error = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $post = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);

    if ($post['name'] === '') {
        $error['name'] = 'blank';
    }
    if ($post['email'] === '') {
        $error['email'] = 'blank';
    }
    if ($post['contact'] === '') {
        $error['contact'] = 'blank';
    }
}
?>
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>お問合せフォーム</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
    <div class="container">
        <form action="" method="POST" novalidate>
            <h4 class="py-4 text-center">お問い合わせ</h4>
            <div class="form-group">
                <div class="row justify-content-center">
                    <div class="col-md-8 col-offset-2">
                        <label for="inputName">お名前(必須)</label>
                    </div>
                    <div class="col-md-8 col-offset-2">
                        <input type="text" name="name" id="inputName" class="form-control rounded-0" value="<?php echo htmlspecialchars($post['name']); ?>" required autofocus>
                        <?php if ($error['name'] === 'blank'): ?>
                            <p class="error_msg text-danger">※お名前をご記入下さい</p>
                        <?php endif; ?>
                    </div>
                </div>
            </div>
            <div class="form-group">
                <div class="row justify-content-center">
                    <div class="col-md-8 col-offset-2">
                        <label for="inputEmail">メールアドレス(必須)</label>
                    </div>
                    <div class="col-md-8 col-offset-2">
                        <input type="email" name="email" id="inputEmail" class="form-control rounded-0" value="<?php echo htmlspecialchars($post['email']); ?>" required>
                        <?php if ($error['email'] === 'blank'): ?>
                            <p class="error_msg text-danger">※メールアドレスをご記入下さい</p>
                        <?php endif; ?>
                    </div>
                </div>
            </div>
            <div class="form-group">
                <div class="row justify-content-center">
                    <div class="col-md-8 col-offset-2">
                        <label for="inputContent">お問い合わせ内容(必須)</label>
                    </div>
                    <div class="col-md-8 col-offset-2">
                        <textarea name="contact" id="inputContent" rows="10" class="form-control rounded-0" required><?php echo htmlspecialchars($post['contact']); ?></textarea>
                        <?php if ($error['contact'] === 'blank'): ?>
                            <p class="error_msg text-danger">※お問い合わせ内容をご記入下さい</p>
                        <?php endif; ?>
                    </div>
                </div>
            </div>
            <div class="row justify-content-center">
                <div class="col-md-8 col-offset-2">
                    <button type="submit" class="btn btn-primary w-100 rounded-0">確認画面へ</button>
                </div>
            </div>
        </form>
    </div>
</body>
</html>

ブラウザを更新し、ご自身で動作確認をしてみてください。

img3.png

メールアドレスのバリデーション

メールアドレスが書式通り(XXXXXX@XXX.XXX)になっているかどうかをチェックします。メールアドレスの条件式に追記します。

index.php
if ($post['email'] === '') {
    $error['email'] = 'blank';
} else if (!filter_var($post['email'], FILTER_VALIDATE_EMAIL)) {
    $error['email']= 'email';
}

メールアドレス入力欄にエラーメッセージを追加します。

index.php
<?php if ($error['email'] === 'email'): ?>
    <p class="error_msg text-danger">※メールアドレスを正しくご記入下さい</p>
<?php endif; ?>

ブラウザを更新し、動作確認をします。

img4.png

正しく動作していることがわかります。これでメールアドレスの書式チェックは完了です。

確認画面への移動

コードを追加します。

index.php
<?php
$error = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $post = filter_input_array(INPUT_POST, FILTER_SANITIZE_STRING);

    if ($post['name'] === '') {
        $error['name'] = 'blank';
    }
    if ($post['email'] === '') {
        $error['email'] = 'blank';
    } else if (!filter_var($post['email'], FILTER_VALIDATE_EMAIL)) {
        $error['email']= 'email';
    }
    if ($post['contact'] === '') {
        $error['contact'] = 'blank';
    }
    // ここから
    if (count($error) === 0) {
        header('Location: confirm.php');
        exit();
    }
    // ここまで
}
?>

これで「確認画面へ」ボタンを押すと、入力した内容に問題がなければconfirm.phpにページが移動します。

まだconfirm.phpを作成していないので、作成しましょう。index.phpの中身をほとんどそのままコピペした内容になっています。

confirm.php
<!DOCTYPE html>
<html lang="ja">
<head>
    <meta charset="UTF-8">
    <title>送信内容確認</title>
    <link rel="stylesheet" href="https://stackpath.bootstrapcdn.com/bootstrap/4.3.1/css/bootstrap.min.css" integrity="sha384-ggOyR0iXCbMQv3Xipma34MD+dH/1fQ784/j6cY/iJTQUOhcWr7x9JvoRxT2MZw1T" crossorigin="anonymous">
</head>
<body>
    <div class="container">
        <form action="./confirm.php" method="POST">
            <h4 class="py-4 text-center">確認画面</h4>
            <div class="form-group">
                <div class="row justify-content-center">
                    <div class="col-md-8 col-offset-2">
                        <label for="inputName">お名前(必須)</label>
                    </div>
                    <div class="col-md-8 col-offset-2">
                        <p>テスト</p>
                    </div>
                </div>
            </div>
            <div class="form-group">
                <div class="row justify-content-center">
                    <div class="col-md-8 col-offset-2">
                        <label for="inputEmail">メールアドレス(必須)</label>
                    </div>
                    <div class="col-md-8 col-offset-2">
                        <p>test@test.com</p>
                    </div>
                </div>
            </div>
            <div class="form-group">
                <div class="row justify-content-center">
                    <div class="col-md-8 col-offset-2">
                        <label for="inputContent">お問い合わせ内容(必須)</label>
                    </div>
                    <div class="col-md-8 col-offset-2">
                        <p>テスト</p>
                    </div>
                </div>
            </div>
            <div class="row justify-content-center">
                <div class="col-md-8 col-offset-2">
                    <a href="index.php" class="btn btn-primary rounded-0">戻る</a>
                    <button type="submit" class="btn btn-primary rounded-0">送信する</button>
                </div>
            </div>
        </form>
    </div>
</body>
</html>

これでindex.phpからconfirm.phpにページが移動できるようになりました。

img5.png

現時点では、index.phpで記入した内容はconfirm.phpに反映されていません。

次回はセッションを有効にし、ページをまたいでも値が保持できるようにしましょう。

PHP入門 - お問い合わせフォームを作ろう (2)

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

Laradock でLaravel + SQLServerの環境を用意する

Laradockの取得

基本は 公式ドキュメント を参照

// 作業用ディレクトリにlaradockをクローンする
git clone https://github.com/Laradock/laradock.git

// envファイルをコピーする
cd laradock
cp env-example .env

本記事は公式ドキュメントの新規作成用のプロジェクト手順に従い、次のディレクトリ構成となる想定です。

作業用フォルダ
  ├ laradock
  └ lara-test(新規プロジェクトフォルダ)

dockerをビルドする前に行う設定

.envの修正

基本設定

APP_CODE_PATH_HOSTに作成予定のプロジェクト名を入力する

APP_CODE_PATH_HOST=../lara-test/

SQL Server用設定

DB名、SA用パスワード、ポート番号を設定する。
パスワードは8文字以上で大文字小文字記号数字の4種類から3種以上含んでいる必要があります。パスワード ポリシー

### MSSQL #################################################

MSSQL_DATABASE=master
MSSQL_PASSWORD="yourStrong(!)Password"
MSSQL_PORT=1433

WORKSPACE用のインストールオプション、PHP_FPM用のインストールオプションをtrueに変更する。

### WORKSPACE #############################################

WORKSPACE_INSTALL_MSSQL=true

### PHP_FPM ###############################################

PHP_FPM_INSTALL_MSSQL=true

それぞれtrueにしないとDB接続時に次のようなエラーが発生します。

Illuminate\Database\QueryException
could not find driver

docker-compose.ymlの修正

ボリュームコンテナーを使用するための修正(Macでのみ必須)

デフォルトでは ${DATA_PATH_HOST} のディレクトリにマウントするように設定されていますが、Macの場合はそのままだとエラーが出ます。

エラー内容
2020-05-08 06:49:33.62 Server      Error: 17113, Severity: 16, State: 1.
2020-05-08 06:49:33.62 Server      Error 87(パラメーターが間違っています。) occurred while opening file '/var/opt/mssql/data/master.mdf' to obtain configuration information at startup. An invalid startup option might have caused the error. Verify your startup options, and correct or remove them if necessary.

2020年6月時点ではMac上ではホストのディレクトリマウントがサポートされていないためです。
https://docs.microsoft.com/ja-jp/sql/linux/sql-server-linux-configure-docker?view=sql-server-ver15#mount-a-host-directory-as-data-volume

現時点では、SQL Server on Linux イメージを使用した Mac 上の Docker のホスト ボリューム マッピングはサポートされていません。 代わりにデータ ボリューム コンテナーを使用してください。

回避するためにはデータボリュームコンテナを用意してそちらを使用する必要があります。

volume定義例
volumes:
  mssqlvolume:
    driver: local
       volumes:
#        - ${DATA_PATH_HOST}/mssql:/var/opt/mssql
        - mssqlvolume:/var/opt/mssql

インストール時に使用される環境変数の変更

設定可能な環境変数はこちら

### MSSQL ################################################
    mssql:
      build:
        context: ./mssql
      environment:
        - MSSQL_PID=Express
        - MSSQL_DATABASE=${MSSQL_DATABASE}
        - SA_PASSWORD=${MSSQL_PASSWORD}
        - ACCEPT_EULA=Y

Developerエディションにするなら MSSQL_PID=Developer に変更、言語を日本語にしたいなら MSSQL_LCID=1041 に変更など。

以降は基本的にMySQLの場合などと同様。
失敗したら、画面に表示されるエラーログや dokcer logsでログを確認する。

コンテナを立ち上げてプロジェクトを作成する

docker-compose up -d workspace nginx mssql php-fpm

でコンテナをビルド & 立ち上げて

docker-compose exec workspace bash

でコンテナに入って

composer create-project --prefer-dist laravel/laravel .

でプロジェクトを作成する。
コンテナ上では /var/www 下にファイルが配置され、ホストPC上ではAPP_CODE_PATH_HOST で設定したプロジェクトフォルダに各ファイルが配置されている状態となります。

コンテナ上にLaravelのファイルが作成される
/var/www# ls -a
.    artisan        composer.lock  .editorconfig  .gitattributes  phpunit.xml  resources   storage       vendor
..   bootstrap      config         .env           .gitignore      public       routes      .styleci.yml  webpack.mix.js
app  composer.json  database       .env.example   package.json    README.md    server.php  tests

この状態で http://localhost を開くとlaravelのデフォルトページが表示されることが確認できます。
image.png

Laravel側のDB設定と疎通確認

Laravel用の.envでSQL Server用の設定をする

新規作成されたlaravelのプロジェクトの.envを編集

DB_CONNECTION=sqlsrv
DB_HOST=laradock_mssql_1
DB_PORT=1433
DB_DATABASE=master
DB_USERNAME=SA
DB_PASSWORD='""yourStrong(!)Password""'

docker-compose.yml のデフォルトのパスワードではダブルクォートが入っていますが、そのまま.envに記載すると除外されてしまうので、上記のような対応が必要です。

疎通確認

routes/web.php

Route::get('/test/', function () {
    return json_encode(\Illuminate\Support\Facades\DB::select("select @@version"));
});

を追加して、 http://localhost/test/ でSQL Serverのバージョン情報が表示されたらSQL Serverに接続ができています。

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

会員制ライブ動画配信サイトの骨組をAWSで作ろう

こんにちは?
今日は、タイトルのことを↓のような方法で実現してみます。


  • S3にHLS動画を置く。パブリックアクセスは許可しない。
  • CloudFront経由でのみ、その動画を再生できるようにする。
    ただし再生にはCloudFrontの暗号鍵で署名したCookieが必要となるよう設定する。
  • CloudFrontにドメインを割り当てる。
  • AWS SDKのCloudFrontクライアントが使えて署名Cookieを操作できる言語(本記事ではPHP)で、動画配信WEBアプリケーションを作る。
  • WEBサーバーに、CloudFrontとセカンドレベルドメインまで同じドメインを割り当てる。
    またCloudFrontの暗号鍵を持たせる。(これでCloudFrontとWEBサーバーで署名Cookieを共有できる)
  • あとは署名Cookie発行をWEBアプリケーションの業務ロジックでコントロールすれば、会員制動画配信が実現可能!(これ以降は本記事では割愛します。)

ついでにCORS対応を施して、
Safari以外のブラウザ(本記事ではChrome)でHLS動画再生も実現します。


正味作業時間はそれほどかかりませんでしたが、

  • つまづきポイントが多い
  • 回避不能な待ち時間が発生する

関係でブヒブヒ言うハメになったので、スクリーンショット付きで詳しく説明していきます。
結構長いですが、お付き合いくださいませ...。

おことわり

本記事中のAWSリソースなどは執筆のために一時的に作成したものです。
流用はできませんので、あしからずご了承くださいませ。

必要なもの

  • AWSアカウント。
    ドメイン取得などを実施するので若干料金が発生します。2,000円くらいあれば十分。
    またドメイン名を何にするか決めておくとスムーズです。
    (本記事の例ではyagrush.netにしています。)

  • シェルが使えてHLS動画が再生できる端末(Macおすすめ。)

  • Docker & docker-compose(Docker Desktopならdocker-composeも付いてくるので、おすすめ。)

  • Chrome

HLS(HTTP Live Streaming)とは

Appleさんが作った動画配信技術。
AbemaTVとかでも使われてるそうです。
本記事ではこのHLSを使っていきます。

昨今の事情に合ったメリットがいっぱいあります。

  • HTTPと相性が良く、一般的なWEBサーバーで動画配信できる。
  • 再生品質をリアルタイム変更できるので安定して配信しやすい。
  • 暗号や認証対応が充実。
    etc...

Safariが一番相性良いですが、他ブラウザでも再生方法はあります。
(後のほうで説明します。)

HLSの動画ファイル形式

.ts.m3u8という拡張子の2種類のファイルで構成されます。
(.mp4 から変換してくれるソフトやオンラインサービスがいっぱいあります。)

.tsファイル

動画データファイル。
1本の動画を数秒単位で細切れにしたもの。
HLS動画はこの .ts ファイル何百何千個で構成されており、しかもそれが再生品質パターン分あったりする。

.m3u8ファイル

HLS動画ファイルのメイン。
山ほどある .ts のファイルパスや再生する順番が記録されている。

ちなみに他の.m3u8ファイルを入れ子にもできる。
例えば、低品質用 .m3u8 にサッと挿げ替えれば、動画再生を止めずに再生品質を下げれたり。

本物のライブ配信システムは .ts をリアルタイムでガシガシ作成していき .m3u8 をガンガン書き換えることで実現しているそうです。

作業開始

.m3u8ファイルと.tsファイルを用意する

いきなり言われても大変ですよね。

そこで、こちらのサイトで公開されているサンプルHLS動画ファイルをお借りします。
すごく使いやすかったので。(もし怒られたら、差し替えします…。)

Adaptive Streamingサンプル

再生品質400K, 2K, 4Kそれぞれ Tears00000~00010.ts の計10個ずつあれば10秒ほど再生できます。
動作確認には十分。

※ 全編だと恐らく.tsファイルが数千個以上あります。
  迷惑をかけるので、無理なダウンロードはやめましょう!

.m3u8

https://tech.jstream.jp/analytics/ex0/all-tears.m3u8
https://tech.jstream.jp/media/ToS/400K/Tears.m3u8
https://tech.jstream.jp/media/ToS/2K/Tears.m3u8
https://tech.jstream.jp/media/ToS/4K/Tears.m3u8

.ts(400K)

https://tech.jstream.jp/media/ToS/400K/Tears00000.ts
https://tech.jstream.jp/media/ToS/400K/Tears00001.ts

https://tech.jstream.jp/media/ToS/400K/Tears00009.ts
https://tech.jstream.jp/media/ToS/400K/Tears00010.ts

.ts(2K)

https://tech.jstream.jp/media/ToS/2K/Tears00000.ts
https://tech.jstream.jp/media/ToS/2K/Tears00001.ts

https://tech.jstream.jp/media/ToS/2K/Tears00009.ts
https://tech.jstream.jp/media/ToS/2K/Tears00010.ts

.ts(4K)

https://tech.jstream.jp/media/ToS/4K/Tears00000.ts
https://tech.jstream.jp/media/ToS/4K/Tears00001.ts

https://tech.jstream.jp/media/ToS/4K/Tears00009.ts
https://tech.jstream.jp/media/ToS/4K/Tears00010.ts

tsファイル00000~00010を一発ダウンロードするシェルの例.悪用しないでね!
URLBASE=https://tech.jstream.jp/media/ToS/400K

mkdir -p media/ToS/400K
cd media/ToS/400K
wget $URLBASE/Tears.m3u8
for i in `seq 0 10`
do
  fileno=`printf %05d $i`
  wget $URLBASE/Tears$fileno.ts
  if [ $? -gt 0 ]; then
    exit 99
  fi
done

cd ../..

S3作業

S3は動画ファイル置き場です。
CloudFront経由かつ特定ドメインからの再生 のみアクセスできるよう、設定を施します。

まずはバケットを作る

スクリーンショット 2020-07-03 16.24.49.png

スクリーンショット 2020-07-03 16.26.46.png

スクリーンショット 2020-07-03 16.28.12.png

CloudFront経由でアクセスするので、パブリックアクセス許可は不要です。

スクリーンショット 2020-07-04 0.44.10.png

HLS動画ファイルをS3にアップロード

サンプル動画の.m3u8に合わせたディレクトリ構造でアップロードしてください。

S3バケット/
  all-tears.m3u8
  media/
   ToS/
    400K/
     Tears.m3u8
     Tears00000.ts
      ...
     Tears00010.ts
    2K/
     Tears.m3u8
     Tears00000.ts
      ...
     Tears00010.ts
    4K/
     Tears.m3u8
     Tears00000.ts
      ...
     Tears00010.ts

CloudFront作業

ここで一旦、CloudFrontの作業に移ります。

CloudFrontは、S3の門番役です。
特定アクセスのみ動画データを転送するよう、色々設定します。

CloudFrontディストリビューション作成

スクリーンショット 2020-07-03 17.03.00.png

スクリーンショット 2020-07-03 17.03.22.png

以下の設定だけを変更して、

設定項目名
Origin Domain Name クリックするとドロップリストが出るので、先ほど作成したS3を選んでください。
Origin ID ドロップリストを選択すれば自動的にセットされると思います。
Ristrict Buchet Access YESを選んでください。
Whitelist Headers 左のリストからOriginを選択して【Add >>】ボタンを押し、右のリストにOriginが移動するようにしてください。
Ristrict Viewer Access YESを選んでください。

それ以外は触らないでOKです。
最後に【Create Distribution】ボタンを押してください。

スクリーンショット 2020-07-03 17.04.39.png

スクリーンショット 2020-07-03 17.06.45.png

スクリーンショット 2020-07-03 17.08.00.png

スクリーンショット 2020-07-03 17.08.19.png

CloudFrontディストリビューションが作成されます。
ちなみにID(本例ではERDBXHEEWQCAE)をクリックすると詳細画面に遷移できます。

スクリーンショット 2020-07-03 17.08.57.png

S3がCloudFrontからのアクセスを許可するのに必要な情報を調べる

Origin Access Identityという値を調べます。
https://docs.aws.amazon.com/ja_jp/AmazonCloudFront/latest/DeveloperGuide/private-content-restricting-access-to-s3.html

これはCloudFrontがS3にアクセスするための特別なユーザーで、ディストリビューション作成したときに自動的に作成されているはずです。

これのIDを控えておいてください。
欄がせまくて途中で見切れていますが、ダブルクリックで全選択→クリップボードなどで確実に控えましょう。

スクリーンショット 2020-07-03 17.21.37.png

再びS3作業

バケットポリシーを設定する

S3のバケットポリシー設定画面を開きます。

スクリーンショット 2020-07-03 17.36.25.png

テキストボックスに↓のJSONコードをコピペしてください。
ただし2箇所、あなたの環境に合わせて変更する必要があります。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Sid": "Grant a CloudFront Origin Identity access",
            "Effect": "Allow",
            "Principal": {
                "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity E1DCCPJY6X9NYO"
            },
            "Action": "s3:GetObject",
            "Resource": "arn:aws:s3:::yagrush-hls/*"
        }
    ]
}
  • "AWS": "arn:aws:iam::cloudfront:user/CloudFront Origin Access Identity のあとに、さきほどコピーしたCFディストリビューションのOrigin Access IdentityのIDを貼り付けてください。
  • "Resource": "arn:aws:s3::: のあとに、あなたが作成したS3のバケット名/*を貼り付けてください。

最後に【保存】ボタンを押してください。
エラーが表示されなければOK。

CORS構成を設定する

CORSとは

異なるサーバー間でリソース(動画とか)を共有できるようにする仕組みです。
これをちゃんと設定しないと、Safari以外のブラウザではS3に置かれたHLS動画を再生できません。
ある意味クロスサイトスクリプティングみたいなことになってしまい、エラーになります。

ちなみにSafariだけは(HLSを開発したAppleさんだけあって)ダイレクトにプラグインが起動してあっけなく再生できてしまいます。

設定する

S3バケットの【アクセス権限】タブから【CORSの設定】画面を開きます。

image.png

↓のXMLをコピペして下さい。
ただ1ヶ所、変更して頂く必要があります。

<?xml version="1.0" encoding="UTF-8"?>
<CORSConfiguration xmlns="http://s3.amazonaws.com/doc/2006-03-01/">
<CORSRule>
    <AllowedOrigin>http://web.yagrush.net:8000</AllowedOrigin>
    <AllowedMethod>GET</AllowedMethod>
    <AllowedMethod>HEAD</AllowedMethod>
    <MaxAgeSeconds>3000</MaxAgeSeconds>
    <AllowedHeader>*</AllowedHeader>
</CORSRule>
</CORSConfiguration>
  • <AllowedOrigin>の中のhttp://web.yagrush.net:8000は、みなさんの環境に合わせて書き換えてください。(トップレベルとセカンドレベルドメイン(本例ではyagrush.net)の部分は、予め決めたものから変えないで下さいね。)

またこの値は、後ほど構築するWEBサーバーのURLに使用するので控えておいてください。

最後に【保存】ボタンを押して下さい。
エラーにならなければOK。

※ XMLのタグを小文字にしたり、<AllowedOrigin>の値の末尾に/が付いてたりするだけですぐエラーになります。かなりセンシティブなので、コピペや編集の際はご注意を。

Route53作業

ドメインを取得する

ちょっと料金がかかります。

また、ここ、ウェイトポイントです!
購入したドメインが有効になるまで数時間かかる場合があります。

では、AWSのRoute53にアクセスしましょう。
そして、ドメインを作成する画面まで進んでください。

スクリーンショット 2020-07-03 17.42.28.png

スクリーンショット 2020-07-03 17.43.13.png

スクリーンショット 2020-07-03 17.43.36.png

指定したドメインが世界でまだ使われていなければOK。
カートに入れて購入します。

スクリーンショット 2020-07-03 17.44.24.png

ドメイン購入は結構ウルサイです。
ちゃんと個人情報を入力しないといけません。
(※ 一度買ったことがあれば、この手順は発生しないと思います。)

スクリーンショット 2020-07-03 17.51.00.png

その後も「規約に同意しろ」とか色々質問が出ますが、ここでは説明は省略します。
無事購入すると、世界中に浸透させる処理が開始されます。

これがまたリアル数時間かかります。
完了するとAWSからメールが来ると思うので、それまで休憩するのも良いでしょう。

スクリーンショット 2020-07-03 17.53.42.png

ドメインが有効になったら続きをやりましょう。

CloudFrontに振るサブドメインを決める

本例ではcf.を付けてcf.yagrush.netにしています。

ドメインとCloudFrontを結びつける

Route53でCNAMEという設定を追加すると、そういうことができます。
別名を登録する感じです。

その前にまずCloudFrontの画面で、CloudFrontディストリビューションのデフォルトアドレスを調べておきましょう。
↓このへんに表示されているやつですね。

image.png

本例ではd14br4vlcj23gd.cloudfront.netです。
※ またもや欄がせまくて途中で見切れているので、クリップボードコピーするときはご注意ください。

Route53にCNAMEレコードを追加する

まずはRoute53の画面を辿って「レコードセットの作成」まで進んでください。

image.png

image.png

image.png

「レコードセットの作成」ボタンを押すと、画面右側に設定小窓が出るので、先ほど調べておいた情報を設定して【作成】ボタンを押します。

image.png

これでOK。

image.png

再びCloudFront作業へ

CloudFront用サーバー証明書を取得する

CloudFrontディストリビューションの詳細設定画面を開いてください。

image.png

image.png

中段あたりにある【Request or Import a Certificate with ACM】ボタンを押して下さい。
image.png

「証明書のリクエスト」画面が開きます。

image.png
まずこのとき、画面右上のリージョン表示が「東京」などではなく「バージニア北部」になっていることを確認してください。(CloudFrontのエンドポイントはバージニア北部にあるため、バージニア北部で取得した証明書じゃないと使えないそうです。罠ポイント。)

それでは、先ほどのCloudFront用サブドメインを入力して【次へ】を押して下さい。
image.png

「DNSの検証」を選択して【次へ】。
image.png

タグは、必要でしたらお好みで設定してください。
【確認】ボタンを押します。
image.png

内容に誤りがなければ【確定とリクエスト】を押して下さい。
image.png

なんだか不安にさせられる画面になりました...
でも大丈夫、【続行】を押して下さい。
image.png

こんな画面に遷移しました。
これまた不穏な...

もちろんこのままではダメです。
画面中段あたり、CloudFront用ドメインの左にある ▼ を押して下さい。

image.png

小窓が展開されます。
その中にあるボタン【Route53でのレコードの作成】を押して下さい。
image.png

【作成】を押して下さい。
image.png

これで処理が進みます。
image.png

はい、来ました!ここもウェイトポイントです!
証明書が使えるようになるまで数時間かかる場合があります...。
(わりとすぐの場合もあります。)

完了すると↓に変わるはずです。
時間をおいてチェックしてみてください。
image.png

OKになったら作業の続きを。

CloudFrontに証明書をセットする

CloudFrontの詳細画面をまた開いてください。

中段あたりのSSL Certificateで、2番目の選択肢Custom SSL Certificate(example.com)がアクティブになり選択できるようになっているはずです。
それを選択しましょう。

※ たまに、証明書OKなのに選択肢Custom SSL Certificate(example.com)がアクティブになるまで時間がかかる場合があるようです...。

そしてその下にあるボックスをクリックするとドロップリストが開き、先ほどの証明書が選択できます。

更にそれらより上の方、Alternate Domain NamesにCloudFront用サブドメインを入力します。

全部終わったら、一番右下の【Yes, Edit】ボタンを押しましょう。
問題なければ、前の画面にスッと戻るはずです。
(もしエラーだと、赤字で下の方に表示されます。)

image.png

CloudFrontキーペアを作成する

今作業をしているAWSアカウントがルートアカウントでない場合、ログアウトしてルートアカウントでAWSコンソールにログインしなおしてください。(ルートアカウントじゃないとできない作業なのです。)

ルートアカウントで画面右上のユーザーメニューから「マイセキュリティ資格情報」を開きます。

image.png

ルートアカウントのみ【CloudFrontのキーペア】というタブが出現します。
それを開くと【新しいキーペアの作成】ボタンがあるので押して下さい。
image.png

image.png

こうなればOK。

  • 【プライベートキーファイルのダウンロード】
  • 【パブリックキーファイルのダウンロード】

は、ダウンロードしておいてください。
後で使います。

後はもうルートアカウントじゃなくてOK。

WEBアプリケーションを作る

以上でAWS作業からは離れます。

次にDockerとPHPを使ってWEBアプリケーションを作りましょう。
動画配信サイトにあたる部分です。

本記事ではローカルに構築して、hostsファイルを書き換えて対応します。
本格的にリモートに構築すると面倒なので...。

hostsを編集する

WEBサーバーのURL(本例ではweb.yagrush.net)をローカル(127.0.0.1)に向けます。

sudo vim /etc/hosts
/etc/hosts.
127.0.0.1   localhost web.yagrush.net

これでweb.yagrush.netのURLでアクセスするかぎり、HLS動画を再生できます。
CloudFrontをだます ...って言い方もアレですけどね。

さすがに記事が辛くなってきた:sob:
あと少し...!

WEBアプリケーション一式セットをダウンロードする

今回、動作確認済のWEBアプリケーション一式セットを予めご用意しました。
https://github.com/yagrush/hls-web

git cloneでもいいですが、ZIPダウンロード&解凍でもOK。
wgetコマンドが使える方は↓の一発コマンドをどうぞ。

wget https://github.com/yagrush/hls-web/archive/master.zip -O hls-web.zip; unzip hls-web.zip; rm -f hls-web.zip

#ついでにディレクトリを移動しておく
cd hls-web-master

CloudFrontのプライベートキーファイルを配備する

前の方の手順でCloudFrontキーペアを作成してプライベートキーファイルをダウンロードしたと思います。
(こんな名前のファイル pk-XXXXXXXXXXXXXXXXXXX.pem
それを hls-web-master/backend/storage/app に置いてください。

設定をカスタマイズする

数か所、みなさんの環境に合わせて変更して頂く必要があります。
(一応目印として**hls**というコメントを付けてあります。)

hls-web-master/backend/resources/views/play_video.blade.php, hls-web-master/backend/app/Http/Controllers/PlayVideoController.php

cf.yagrush.netyagrush.netの部分を、みなさんのケースに合わせて書き換えて下さい。

hls-web-master/backend/app/Http/Controllers/PlayVideoController.php

みなさんのCloudFrontキーペアのプライベートキーファイル名に合わせてXXXXXXXXXXXXXXXXXXXの部分を書き換えて下さい。
ちなみにキーペアIDも、プライベートキーファイル名のXXXXXXXXXXXXXXXXXXXと同じです。

hls-web-master/backend/resources/views/play_video.blade.php
...
...
    var videoSrc = 'https://cf.yagrush.net/all-tears.m3u8'; //**hls**
...
...
hls-web-master/backend/app/Http/Controllers/PlayVideoController.php
...
...
        $resourceKey = "https://cf.yagrush.net/*"; //**hls**
...
...
            'private_key' => storage_path() . '/app/pk-XXXXXXXXXXXXXXXXXXX.pem', //**hls**
            'key_pair_id' => 'XXXXXXXXXXXXXXXXXXX' //**hls**
...
...
        $domain = 'yagrush.net';  //**hls**
...
...

起動

hls-web-master/で以下のコマンドを打ってください。(数分かかるかも。)

make init

問題なければ、

  • ポート8000でnginxコンテナがWEBサーバーのフロントとして起動します。
  • PHPを処理するためのバックエンドとしてphp-fpmコンテナが起動します。
  • Laravelフレームワークのためだけにポート3306でmysqlコンテナが起動しますが、気にしないでください。

もしポート被りで起動に失敗したら、hls-web-master/docker-compose.ymlを編集してポートを変更するなどしてくださいね。

動画再生してみる

動画再生ページにChromeでアクセスしてみて下さい。
(本例だと http://web.yagrush.net:8000/play_video

再生されましたでしょうか?
↓こんな感じ。

image.png

今回は動画データの一部だけしか配備してないので、10秒ほどで停止します。

お時間あればSafariでもアクセスしてみて下さい。
ちなみにSafari以外での再生のために hls.js を採用しました。

動画に直アクセスできないのを確認してみる

以下のコマンドでcookieを使わずにアクセスしてみます。
(例によってyagrush.netはみなさんの環境に合わせて書き換えて下さいね。)

まずはOriginヘッダを付けて送信してみます。

curl -X GET -H 'Origin: http://web.yagrush.net:8000' -i -v -f https://cf.yagrush.net/all-tears.m3u8

403エラー!
拒否されちゃいました。

Note: Unnecessary use of -X or --request, GET is already inferred.
*   Trying xxx.xxx.xxx.xxx...
* TCP_NODELAY set
* Connected to cf.yagrush.net (xxx.xxx.xxx.xxx) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* successfully set certificate verify locations:
*   CAfile: /etc/ssl/cert.pem
  CApath: none
* TLSv1.2 (OUT), TLS handshake, Client hello (1):
* TLSv1.2 (IN), TLS handshake, Server hello (2):
* TLSv1.2 (IN), TLS handshake, Certificate (11):
* TLSv1.2 (IN), TLS handshake, Server key exchange (12):
* TLSv1.2 (IN), TLS handshake, Server finished (14):
* TLSv1.2 (OUT), TLS handshake, Client key exchange (16):
* TLSv1.2 (OUT), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (OUT), TLS handshake, Finished (20):
* TLSv1.2 (IN), TLS change cipher, Change cipher spec (1):
* TLSv1.2 (IN), TLS handshake, Finished (20):
* SSL connection using TLSv1.2 / ECDHE-RSA-AES128-GCM-SHA256
* ALPN, server accepted to use h2
* Server certificate:
*  subject: CN=cf.yagrush.net
*  start date: Jul  3 00:00:00 2020 GMT
*  expire date: Aug  3 12:00:00 2021 GMT
*  subjectAltName: host "cf.yagrush.net" matched certs "cf.yagrush.net"
*  issuer: C=US; O=Amazon; OU=Server CA 1B; CN=Amazon
*  SSL certificate verify ok.
* Using HTTP2, server supports multi-use
* Connection state changed (HTTP/2 confirmed)
* Copying HTTP/2 data in stream buffer to connection buffer after upgrade: len=0
* Using Stream ID: 1 (easy handle 0xxxxxxxxxxxxx)
> GET /all-tears.m3u8 HTTP/2
> Host: cf.yagrush.net
> User-Agent: curl/7.64.1
> Accept: */*
> Origin: http://web.yagrush.net:8000
> 
* Connection state changed (MAX_CONCURRENT_STREAMS == 128)!
* The requested URL returned error: 403 
* stopped the pause stream!
* Connection #0 to host cf.yagrush.net left intact
curl: (22) The requested URL returned error: 403 
* Closing connection 0

今度はプライベートキーファイルまで付けて送信してみます。

curl -X GET -H 'Origin: http://web.yagrush.net:8000' -i -v -f -E backend/storage/app/pk-XXXXXXXXXXXXXXXXXX.pem https://cf.yagrush.net/all-tears.m3u8

やはり怒られました。

Note: Unnecessary use of -X or --request, GET is already inferred.
*   Trying xxx.xxx.xxx.xxx...
* TCP_NODELAY set
* Connected to sample.flhls.net (xxx.xxx.xxx.xxx) port 443 (#0)
* ALPN, offering h2
* ALPN, offering http/1.1
* could not load PEM client certificate, LibreSSL error error:09FFF06C:PEM routines:CRYPTO_internal:no start line, (no key found, wrong pass phrase, or wrong file format?)
* Closing connection 0
curl: (58) could not load PEM client certificate, LibreSSL error error:09FFF06C:PEM routines:CRYPTO_internal:no start line, (no key found, wrong pass phrase, or wrong file format?)

終了

以下のコマンドでWEBアプリケーションを終了&破棄します。

make destroy

おつかれさまでしたぁーー!!!

WEBアプリケーション変更点 まとめ

今回は、定番のこちら -> 最強のLaravel開発環境をDockerを使って構築する【新編集版】 をベースに以下の手を加えました。

PHP用AWS SDKインストールをビルド工程(Makefile @ create-project)に追加。

docker-compose exec app composer require aws/aws-sdk-php

★ CloudFrontキーペアのプライベートキーファイルをbackend/storage/appに配備。

backend/routes/web.phpにルーティング設定追記。

Route::get('/play_video', 'PlayVideoController@show');

★ ソースコード2つ作成。

  • backend/app/Http/Controllers/PlayVideoController.php
  • backend/resources/views/play_video.blade.php

CloudFront+S3+Video.js+ 署名付きCookieでクローズドな動画配信 を参考に書きました。
↑お時間あれば是非ご覧になってみて下さい。

参考文献

今回はこれらのサイトにお世話になりました。
ありがとうございます。

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

新人3ヶ月エンジニアが学んだPHP関数

新人3ヶ月エンジニアが学んだPHP関数

スクールでRailsを学び、晴れWebエンジニアになった私ですが
使用するフレームワークはLarabel 言語はPHPでした。
プロゲートでPHPを一周やって、あとはLaravelを触り続ける毎日で実務に突入したのですが
PHP関数は「ナンモワカラン」状態で、コードを読むのが大変だったので備忘録的に実務で使用していたPHP関数をまとめて置きたいと思います。

array_column() 

array_column(配列, ‘カラム名’, ‘カラム名’)

配列から単一のカラムの値を返す

array_values ()

array_values ( 配列 ) 

配列から全ての値を取り出し、数値添字をつけた配列を返します。

array_unique()

array_unique ( array $array [, int $sort_flags = SORT_STRING ] ) : array

配列から重複した値を削除する

array_merge()

 array_merge([配列],$配列)

ひとつまたは複数の配列を結合する

array_search

array_search(検索ワード、検索配列)

指定した値を配列で検索し、見つかった場合に対応する最初のキーを返す

strpos()

strpos(検索文字列、検索ワード、検索開始位置) 

文字列内の部分文字列が最初に現れる場所を見つける

curl_init()

 $curl = curl_init();

新しい cURL リソースを作成します

curl_setopt_array()

 curl_setopt_array($curl, $options);

CURL 転送用の複数のオプションを設定する

curl_exec($curl)

 $result = curl_exec($curl);

指定した cURL セッションを実行します。

curl_close($curl)

curl_close($curl);

cURL セッションを閉じる

implode()

implode ( 文字列 , 配列 )

配列要素を文字列により連結する

mb_substr()

mb_substr(部分文字列を取り出したい文字列,数値, 最大文字数、エンコーディング)

文字列の一部を得る

explode

explode(‘区切る文字, 区切られる配列);

explode — 文字列を文字列により分割する

implode()

implode ( ‘ ’ , 連結したい配列 )

implode — 配列要素を文字列により連結する

str_replace()

str_replace(検索したい文字列 ,  置き換える文字列文字 ,  置換したい文字列 ) 

str_replace — 検索文字列に一致したすべての文字列を置換する

strip_tags

strip_tags(HTML要素などを含んだ文字列);

strip_tags — 文字列から HTML および PHP タグを取り除く
この関数は、指定した文字列 (str) から全ての NULL バイトと HTML および PHP タグを取り除きます。

preg_split()

preg_split("//u", $string, -1, PREG_SPLIT_NO_EMPTY); 

preg_split — 正規表現で文字列を分割する

あとがき

PHP関数は多すぎて覚えれませんよね。
サービスで使用されているPHP関数のみまとめてくれていたら事前に予習でき楽だなと思い、記事作成に至りました。
これだけでは無いのでゆっくり追記していこうと思ってます!!

ほぼ、下記参考を参考にしています。
https://www.php.net/manual/ja/function.str-replace.php

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

なんで自鯖のフォントファイルをサイトビルダーで使えないんじゃ^~

経緯

某Webサイトビルダーでサイトタイトルにフォントを使いたい
  ↓
カスタムコード機能でCSSを記述する

@font-face {
   font-family: "custom-font";
   src: url("https://my-rental-server.sample/font/tsukaitai.ttf");
}
h1#kakkoii-title {
   font-family: custom-font, sans-selif;
}

  ↓
chrome先生「Access to font at 'https://my-rental-server.sample/font/tsukaitai.ttf' from origin 'https://suitbuilder.sample' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource.
  ↓
僕「ぴえん」

HeaderでCORSの許可(よくわかってない)

ファイルのヘッダーでCORSの許可(?)を与えるといいらしい。
.htaccessがよくわかってない脆弱エンジニアな僕「ヘッダーを記述するならPHPだな?(名案」

解決

フォントファイルのあるフォルダにこんなPHPを用意した。

readfont.php
<?php 
header('Access-Control-Allow-Origin: *');
echo file_get_contents($_GET['a']);
?>

そしてサイトビルダーのカスタムコードの@font-faceはこんな感じ

@font-face {
   font-family: "custom-font";
   src: url("https://my-rental-server.sample/font/readfont?a=tsukaitai.ttf") format("truetype");
}
/* 以下略 */

結果

絶対に正解じゃないけど、解決したのでヨシ!

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