20190727のPHPに関する記事は14件です。

php-master-changes 2019-07-26

今日は run-tests.php の修正、ドキュメントの修正があった!

2019-07-26

morrisonlevi: Remove .post files only for passing tests

cmb69: Remove duplication

theodorejb: Fix typos in UPGRADING and improve wording in a few places

petk: Mention also API versions bumps

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

PHP 配列・イテレータ ドキュメント

このページについて

配列やイテレータに関するインターフェースのドキュメントリンク集です。

PHP マニュアル > 関数リファレンス
https://www.php.net/manual/ja/funcref.php

PHP マニュアル > 関数リファレンス > その他の基本モジュール > JavaScript Object Notation
https://www.php.net/manual/ja/book.json.php

PHP マニュアル > 関数リファレンス > その他の基本モジュール > Standard PHP Library (SPL)
https://www.php.net/manual/ja/book.spl.php

PHP マニュアル > 言語リファレンス
https://www.php.net/manual/ja/langref.php

配列

ArrayAccess インターフェイス

https://www.php.net/manual/ja/class.arrayaccess.php

配列としてオブジェクトにアクセスするための機能のインターフェイスです。

ArrayObject クラス

https://www.php.net/manual/ja/class.arrayobject.php

このクラスは、オブジェクトを配列として動作させます。

Countable インターフェイス

https://www.php.net/manual/ja/class.countable.php

Countable を実装したクラスは、 count() 関数で使用することができます。

ジェネレータ

https://www.php.net/manual/ja/language.generators.syntax.php

ジェネレータ関数の見た目はふつうの関数とほぼ同じです。違うのは、値を返すのではなく、 必要なだけ値を yield することです。

ジェネレータ関数が呼ばれると、反復処理が可能なオブジェクトを返します。 このオブジェクトを (foreach ループなどで) 反復させると、 値が必要になるたびに PHP がジェネレータ関数を呼びます。 そして、ジェネレータが値を yield した時点の状態を保存しておき、 次に値が必要になったときにはそこから再開できるようにします。

yield できる値がなくなると、ジェネレータ関数は何もせず単純に終了します。 呼び出し元のコードでは、配列の要素をすべて処理し終えた後のように、そのまま処理が続きます。

イテレータ

Iterator インターフェイス

https://www.php.net/manual/ja/class.iterator.php

外部のイテレータあるいはオブジェクト自身から反復処理を行うためのインターフェイスです。

IteratorAggregate インターフェイス

https://www.php.net/manual/ja/class.iteratoraggregate.php

外部イテレータを作成するためのインターフェイスです。

OuterIterator インターフェイス

https://www.php.net/manual/ja/class.outeriterator.php

OuterIterator を実装したクラスは、 イテレータ群の反復処理に使うことができます。

RecursiveIterator インターフェイス

https://www.php.net/manual/ja/class.recursiveiterator.php

RecursiveIterator を実装したクラスは、 イテレータ群を再帰的に反復処理するときに使うことができます。

SeekableIterator インターフェイス

https://www.php.net/manual/ja/class.seekableiterator.php

Seekable イテレータです。

SPL イテレータ

https://www.php.net/manual/ja/spl.iterators.php

SPL にはイテレータが用意されており、オブジェクトを反復処理することができます。

SPL イテレータクラスツリー

ArrayIterator
    RecursiveArrayIterator

EmptyIterator
IteratorIterator
    AppendIterator
    CachingIterator
        RecursiveCachingIterator
    FilterIterator
        CallbackFilterIterator
            RecursiveCallbackFilterIterator
        RecursiveFilterIterator
            ParentIterator
        RegexIterator
            RecursiveRegexIterator

    InfiniteIterator
    LimitIterator
    NoRewindIterator

MultipleIterator
RecursiveIteratorIterator
    RecursiveTreeIterator

DirectoryIterator (extends SplFileInfo)
    FilesystemIterator
        GlobIterator
        RecursiveDirectoryIterator

データ構造

https://www.php.net/manual/ja/spl.datastructures.php

SPL では、標準的なデータ構造を提供しています。 ここで、それらを実装ごとに分類してまとめます。

双方向リンクリスト

https://www.php.net/manual/ja/class.spldoublylinkedlist.php

双方向リンクリスト (Doubly Linked List: DLL) は、双方向のノードへのリンクを持つノードのリストです。 イテレータの操作、両隣へのアクセス、ノードの追加や削除のコストは、 データ構造が DLL の場合は O(1) となります。 これは、スタックやキューを実装するのに適しています。

SplDoublyLinkedList
    SplStack
    SplQueue

ヒープ

https://www.php.net/manual/ja/class.splheap.php
https://www.php.net/manual/ja/class.splpriorityqueue.php

ヒープは、ツリー風の構造です。ヒープ特有の性質として、 個々のノードはその子ノードと等しいかそれより大きな値となります。 値の比較は、ヒープ全体の比較メソッドとして実装されているものを使用します。

SplHeap
    SplMaxHeap
    SplMinHeap

SplPriorityQueue

配列

https://www.php.net/manual/ja/class.splfixedarray.php

配列は、データを連続的に格納してインデックス経由でアクセスできるようにした構造です。 PHP の配列と混同しないようにしましょう。PHP の配列は、 実際のところは順序つきハッシュテーブルとして実装されています。

SplFixedArray

マップ

https://www.php.net/manual/ja/spl.datastructures.php

マップは、キー/値 のペアからなるデータ構造です。 PHP の配列は、整数値/文字列を値と対応させたマップとみなすことができます。 SPL では、オブジェクトとデータを対応させるマップを提供しています。 このマップは、オブジェクトの集合として扱うことができます。

SplObjectStorage

Observer パターン

SplObserver インターフェイス

https://www.php.net/manual/ja/class.splobserver.php

SplObserver インターフェイスを SplSubject とともに使うと、Observer パターンを実装することができます。

SplSubject インターフェイス

https://www.php.net/manual/ja/class.splsubject.php

SplSubject インターフェイスを SplObserver とともに使うと、Observer パターンを実装することができます。

SPL 関数

https://www.php.net/manual/ja/ref.spl.php

iterator_apply

https://www.php.net/manual/ja/function.iterator-apply.php

ユーザー関数をイテレータのすべての要素でコールする

iterator_count

https://www.php.net/manual/ja/function.iterator-count.php

イテレータにある要素をカウントする

iterator_to_array

https://www.php.net/manual/ja/function.iterator-to-array.php

イテレータを配列にコピーする

データ保存関連

Serializable インターフェイス

https://www.php.net/manual/ja/class.serializable.php

独自のシリアライズ用のインターフェイスです。

このインターフェイスを実装したクラスは sleep() や __wakeup() をサポートしなくなります。 シリアライズが必要な場合には、自動的に serialize メソッドがコールされます。 このメソッドは __destruct() を実行しません。また、 メソッド内で明示的に書かない限りは一切の副作用を及ぼしません。 アンシリアライズされるときにはそのクラスが自動的に検知し、construct() メソッドのかわりに適切な unserialize() メソッドがコールされます。 標準のコンストラクタを実行させたい場合は、unserialize() メソッドの中でそれをコールします。

JsonSerializable インターフェイス

https://www.php.net/manual/ja/class.jsonserializable.php

JsonSerializable を実装したオブジェクトは、 json_encode() を呼んで処理されたときの自身の JSON 表現をカスタマイズできます。

あまり意識することのないクラス

Generator クラス

https://www.php.net/manual/ja/class.generator.php

Generator は ジェネレータ が返すオブジェクトです。

Closure クラス

https://www.php.net/manual/ja/class.closure.php

無名関数 を表すために使うクラスです。

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

PHP

このページについて

配列やイテレータに関するインターフェースのドキュメントリンク集です。

PHP マニュアル > 関数リファレンス
https://www.php.net/manual/ja/funcref.php

PHP マニュアル > 関数リファレンス > その他の基本モジュール > JavaScript Object Notation
https://www.php.net/manual/ja/book.json.php

PHP マニュアル > 関数リファレンス > その他の基本モジュール > Standard PHP Library (SPL)
https://www.php.net/manual/ja/book.spl.php

PHP マニュアル > 言語リファレンス
https://www.php.net/manual/ja/langref.php

配列

ArrayAccess インターフェイス

https://www.php.net/manual/ja/class.arrayaccess.php

配列としてオブジェクトにアクセスするための機能のインターフェイスです。

ArrayObject クラス

https://www.php.net/manual/ja/class.arrayobject.php

このクラスは、オブジェクトを配列として動作させます。

Countable インターフェイス

https://www.php.net/manual/ja/class.countable.php

Countable を実装したクラスは、 count() 関数で使用することができます。

ジェネレータ

https://www.php.net/manual/ja/language.generators.syntax.php

ジェネレータ関数の見た目はふつうの関数とほぼ同じです。違うのは、値を返すのではなく、 必要なだけ値を yield することです。

ジェネレータ関数が呼ばれると、反復処理が可能なオブジェクトを返します。 このオブジェクトを (foreach ループなどで) 反復させると、 値が必要になるたびに PHP がジェネレータ関数を呼びます。 そして、ジェネレータが値を yield した時点の状態を保存しておき、 次に値が必要になったときにはそこから再開できるようにします。

yield できる値がなくなると、ジェネレータ関数は何もせず単純に終了します。 呼び出し元のコードでは、配列の要素をすべて処理し終えた後のように、そのまま処理が続きます。

イテレータ

Iterator インターフェイス

https://www.php.net/manual/ja/class.iterator.php

外部のイテレータあるいはオブジェクト自身から反復処理を行うためのインターフェイスです。

IteratorAggregate インターフェイス

https://www.php.net/manual/ja/class.iteratoraggregate.php

外部イテレータを作成するためのインターフェイスです。

OuterIterator インターフェイス

https://www.php.net/manual/ja/class.outeriterator.php

OuterIterator を実装したクラスは、 イテレータ群の反復処理に使うことができます。

RecursiveIterator インターフェイス

https://www.php.net/manual/ja/class.recursiveiterator.php

RecursiveIterator を実装したクラスは、 イテレータ群を再帰的に反復処理するときに使うことができます。

SeekableIterator インターフェイス

https://www.php.net/manual/ja/class.seekableiterator.php

Seekable イテレータです。

SPL イテレータ

https://www.php.net/manual/ja/spl.iterators.php

SPL にはイテレータが用意されており、オブジェクトを反復処理することができます。

SPL イテレータクラスツリー

ArrayIterator
    RecursiveArrayIterator

EmptyIterator
IteratorIterator
    AppendIterator
    CachingIterator
        RecursiveCachingIterator
    FilterIterator
        CallbackFilterIterator
            RecursiveCallbackFilterIterator
        RecursiveFilterIterator
            ParentIterator
        RegexIterator
            RecursiveRegexIterator

    InfiniteIterator
    LimitIterator
    NoRewindIterator

MultipleIterator
RecursiveIteratorIterator
    RecursiveTreeIterator

DirectoryIterator (extends SplFileInfo)
    FilesystemIterator
        GlobIterator
        RecursiveDirectoryIterator

データ構造

https://www.php.net/manual/ja/spl.datastructures.php

SPL では、標準的なデータ構造を提供しています。 ここで、それらを実装ごとに分類してまとめます。

双方向リンクリスト

https://www.php.net/manual/ja/class.spldoublylinkedlist.php

双方向リンクリスト (Doubly Linked List: DLL) は、双方向のノードへのリンクを持つノードのリストです。 イテレータの操作、両隣へのアクセス、ノードの追加や削除のコストは、 データ構造が DLL の場合は O(1) となります。 これは、スタックやキューを実装するのに適しています。

SplDoublyLinkedList
    SplStack
    SplQueue

ヒープ

https://www.php.net/manual/ja/class.splheap.php
https://www.php.net/manual/ja/class.splpriorityqueue.php

ヒープは、ツリー風の構造です。ヒープ特有の性質として、 個々のノードはその子ノードと等しいかそれより大きな値となります。 値の比較は、ヒープ全体の比較メソッドとして実装されているものを使用します。

SplHeap
    SplMaxHeap
    SplMinHeap

SplPriorityQueue

配列

https://www.php.net/manual/ja/class.splfixedarray.php

配列は、データを連続的に格納してインデックス経由でアクセスできるようにした構造です。 PHP の配列と混同しないようにしましょう。PHP の配列は、 実際のところは順序つきハッシュテーブルとして実装されています。

SplFixedArray

マップ

https://www.php.net/manual/ja/spl.datastructures.php

マップは、キー/値 のペアからなるデータ構造です。 PHP の配列は、整数値/文字列を値と対応させたマップとみなすことができます。 SPL では、オブジェクトとデータを対応させるマップを提供しています。 このマップは、オブジェクトの集合として扱うことができます。

SplObjectStorage

Observer パターン

SplObserver インターフェイス

https://www.php.net/manual/ja/class.splobserver.php

SplObserver インターフェイスを SplSubject とともに使うと、Observer パターンを実装することができます。

SplSubject インターフェイス

https://www.php.net/manual/ja/class.splsubject.php

SplSubject インターフェイスを SplObserver とともに使うと、Observer パターンを実装することができます。

SPL 関数

https://www.php.net/manual/ja/ref.spl.php

iterator_apply

https://www.php.net/manual/ja/function.iterator-apply.php

ユーザー関数をイテレータのすべての要素でコールする

iterator_count

https://www.php.net/manual/ja/function.iterator-count.php

イテレータにある要素をカウントする

iterator_to_array

https://www.php.net/manual/ja/function.iterator-to-array.php

イテレータを配列にコピーする

データ保存関連

Serializable インターフェイス

https://www.php.net/manual/ja/class.serializable.php

独自のシリアライズ用のインターフェイスです。

このインターフェイスを実装したクラスは sleep() や __wakeup() をサポートしなくなります。 シリアライズが必要な場合には、自動的に serialize メソッドがコールされます。 このメソッドは __destruct() を実行しません。また、 メソッド内で明示的に書かない限りは一切の副作用を及ぼしません。 アンシリアライズされるときにはそのクラスが自動的に検知し、construct() メソッドのかわりに適切な unserialize() メソッドがコールされます。 標準のコンストラクタを実行させたい場合は、unserialize() メソッドの中でそれをコールします。

JsonSerializable インターフェイス

https://www.php.net/manual/ja/class.jsonserializable.php

JsonSerializable を実装したオブジェクトは、 json_encode() を呼んで処理されたときの自身の JSON 表現をカスタマイズできます。

あまり意識することのないクラス

Generator クラス

https://www.php.net/manual/ja/class.generator.php

Generator は ジェネレータ が返すオブジェクトです。

Closure クラス

https://www.php.net/manual/ja/class.closure.php

無名関数 を表すために使うクラスです。

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

AWS Cloud9にSymfonyを構築する

テスト環境としてSymfonyが使える環境が欲しいと思い、Cloud9上に構築してみました。
今回構築したときの備忘録です。

PHPのインストール

Cloud9のOSは、2019年7月時点でAmazon Linux2ではなく、以前のAmazon Linuxでした。
なので、amazon-linux-extrasは使えませんでした。

$ cat /etc/system-release
Amazon Linux AMI release 2018.03
$ sudo yum -y update
$ sudo yum -y install php72 php72-mbstring php72-pdo
$ sudo unlink /usr/bin/php
$ sudo ln -s /etc/alternatives/php7 /usr/bin/php
$ php -v
PHP 7.2.19 (cli) (built: Jun 12 2019 20:55:29) ( NTS )
Copyright (c) 1997-2018 The PHP Group
Zend Engine v3.2.0, Copyright (c) 1998-2018 Zend Technologies

https://qiita.com/kidatti/items/2d6a4a24f89dc71eb66e

Symfonyのインストール

$ wget https://get.symfony.com/cli/installer -O - | bash
$ export PATH="$HOME/.symfony/bin:$PATH" >> .bash_profile
$ sudo mv /home/ec2-user/.symfony/bin/symfony /usr/local/bin/symfony
$ source .bash_profile
$ symfony -v
Symfony CLI version v4.6.2 (c) 2017-2019 Symfony SAS

https://symfony.com/download

Composerのインストール

$ php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
$ php -r "if (hash_file('sha384', 'composer-setup.php') === '48e3236262b34d30969dca3c37281b3b4bbe3221bda826ac6a9a62d6444cdb0dcd0615698a5cbe587c3f0fe57a54d8f5') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;"
$ php composer-setup.php
$ php -r "unlink('composer-setup.php');"
$ sudo mv composer.phar /usr/local/bin/composer
$ composer -v
   ______
  / ____/___  ____ ___  ____  ____  ________  _____
 / /   / __ \/ __ `__ \/ __ \/ __ \/ ___/ _ \/ ___/
/ /___/ /_/ / / / / / / /_/ / /_/ (__  )  __/ /
\____/\____/_/ /_/ /_/ .___/\____/____/\___/_/
                    /_/
Composer version 1.8.6 2019-06-11 15:03:05

https://getcomposer.org/download/
http://symdoc.kwalk.jp/doc/book/installation

Symfonyの起動

Cloud9では外部からアクセスできるポート番号が決まっているため、ポート番号を指定して起動する必要があります。

$ symfony new --full my_project
$ cd my_project/
$ php bin/console server:start *:8080

メニュー > Preview > Preview Running Applicationを押すと実行ページのプレビューが表示されます。

Symfonyの停止

$ php bin/console server:stop

(補足)アプリの状態をするコマンド

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

PHPのdate関数にいろんなものを突っ込んでみた

PHPのdate関数にいろんなものを突っ込んだ時のテスト
日付が1日足りない場合の時の挙動なんかおもしろいかも。

echo $birth . ':' . date('Y/m/d H:i:s', strtotime($birth));    //:1970/01/01 09:00:00

日付形式に変換できないものは「1970/01/01 09:00:00」になるみたいです。

    $birth = null;
    echo $birth . ':' . date('Y/m/d', strtotime($birth));    //:1970/01/01

    $birth = '';
    echo $birth . ':' . date('Y/m/d', strtotime($birth));    //:1970/01/01

    $birth = 'あああ';
    echo $birth . ':' . date('Y/m/d', strtotime($birth));    //1999/99/99:1970/01/01

    $birth = '1999/99/99';
    echo $birth . ':' . date('Y/m/d', strtotime($birth));    //1999/99/99:1970/01/01

    $birth = '1999/00/00';
    echo $birth . ':' . date('Y/m/d', strtotime($birth));    //1999/00/00:1998/11/30

    $birth = '0000/00/00';
    echo $birth . ':' . date('Y/m/d', strtotime($birth));    //0000/00/00:-0001/11/30

    $birth = '1999/01/01';
    echo $birth . ':' . date('Y/m/d', strtotime($birth));    //1999/01/01:1999/01/01

[/php]


0000の場合は日付がずれるみたいです
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPのcurlでLocationを辿ろうとしたらエラー

curlのリダイレクトに対応するために、curl_setoptで

CURLOPT_FOLLOWLOCATIONを設定しようとしたらこんなエラーがでました。

CURLOPT_FOLLOWLOCATION cannot be activated when safe_mode is enabled or an open_basedir is set in /home/***/***/test.php on line 123

原因はPHPが動いているレンタルサーバーがセーフモードで実行していたためでした。
curlでLocationをたどるために以下の方法を使いました。

    $ch = curl_init();
    $limit = 5;
    $url = "http://example.com/has/some/redirect";
    do {
        curl_setopt($ch, CURLOPT_URL, $url);
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
        $response = curl_exec($ch);
        $code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
        $url = curl_getinfo($ch, CURLINFO_REDIRECT_URL);
    } while ($code === 301 || $code === 302 and $limit--);
``
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPで画像添付メール送信

メールを送信する前に画像のサイズ、形式のチェックをします。

input.php

<?php

    header('Content-type: text/html; charset=UTF-8');

    //メッセージ取得初期化
    $MESSAGE     = isset($_COOKIE['MESSAGE']) ? $_COOKIE['MESSAGE'] : NULL;
    setcookie('MESSAGE',     '',     time() + 3600, '/');

?>

<?=nl2br($MESSAGE);?>

<form method="POST" action="upload.php" enctype="multipart/form-data">

    <input type="file" name="upimg" accept="image/*">
    <input type="submit">

</form>

upload.php

<?php

    header('Content-type: text/html; charset=UTF-8');

    try {

        $ERRMSG = NULL;

        //―――――――――――――――――――――――――――――――――――
        //送信画像チェック
        //―――――――――――――――――――――――――――――――――――
        $IMGNAME =     isset($_FILES['upimg']['name'])     ? $_FILES['upimg']['name'] : NULL;
        $IMGTMP =      isset($_FILES['upimg']['tmp_name']) ? $_FILES['upimg']['tmp_name'] : NULL;
        $IMGUPERR = isset($_FILES['upimg']['error'])     ? $_FILES['upimg']['error'] : NULL;

        $fp = @fopen($IMGTMP, "rb");
        $img = @fread($fp, filesize($IMGTMP));
        @fclose($fp);

        $IMGSIZE = floor(strlen($img) / 1024);
        $ENCODEIMG = base64_encode($img);

        $imginfo = @getimagesize('data:application/octet-stream;base64,' . $ENCODEIMG);
        $IMGTYPE = $imginfo['mime'];

        $INPERRFLG = 0;
        $INPERRMSG = NULL;

        if($IMGUPERR == UPLOAD_ERR_NO_FILE){
            $INPERRFLG = 1;
            $INPERRMSG .= 'ファイルを選択してください' . "\n";
        }else if($IMGUPERR == UPLOAD_ERR_PARTIAL){
            $INPERRFLG = 1;
            $INPERRMSG .= 'ファイルのアップに失敗しました。' . "\n";
        }else if($IMGUPERR == UPLOAD_ERR_INI_SIZE || $IMGUPERR == UPLOAD_ERR_FORM_SIZE){
            $INPERRFLG = 1;
            $INPERRMSG .= 'ファイルサイズが大きすぎます' . "\n";
        }else{

            if($IMGTYPE == 'image/gif' || $IMGTYPE == 'image/jpeg' || $IMGTYPE == 'image/png'){
            }else{
                $INPERRFLG = 1;
                $INPERRMSG .= '画像を選択してください。' . "\n";
            }
            if(!preg_match('/^.*\.(jpg|jpeg|gif|png)$/i', $IMGNAME)){
                $INPERRFLG = 1;
                $INPERRMSG .= 'jpg、gif、pngの拡張子を選択してください。' . "\n";
            }
            if($IMGSIZE > 1024){
                $INPERRFLG = 1;
                $INPERRMSG .= 'サイズを1MB以下にしてください。' . "\n";
            }

        }

        if($INPERRFLG == 1){
            setcookie('MESSAGE',     $INPERRMSG,     time() + 3600, '/');
            header('Location: http://' . $_SERVER['SERVER_NAME'] . '/input.php');
            exit;
        }

        //―――――――――――――――――――――――――――――――――――
        //メール送信
        //―――――――――――――――――――――――――――――――――――
        $BOUNDARY = '__BOUNDARY__' .md5(rand());

        $to = 'webmaster@example.com';
        $subject = '件名';
        $header = implode("\r\n",array(
            'Content-Type: multipart/mixed;boundary=' . $BOUNDARY ,
            'From: webmaster@example.com',
            'Reply-To: webmaster@example.com',
        ));

        $body = "--" . $BOUNDARY . "\n";
        $body .= 'Content-Type: text/plain; charset="ISO-2022-JP' . "\n";
        $body .= '画像が送信されました。' . "\n";

        $body .= '--' . $BOUNDARY . "\n";
        $body .= 'Content-Type: ' . $IMGTYPE . '; name=' . $IMGNAME . "\n";
        $body .= 'Content-Disposition: attachment; filename=' . $IMGNAME . "\n";
        $body .= 'Content-Transfer-Encoding: base64' . "\n";
        $body .= chunk_split($ENCODEIMG) . "\n";
        $body .= '--' . $BOUNDARY . '--';

        mail($to, $subject, $body, $header);


    } catch (Exception $e) {
        $ERRMSG = $e->getMessage();
    }

?>
<?php if(mb_strlen($ERRMSG) > 0) : ?>

    <p><?=$ERRMSG;?></p>

<?php else : ?>

    <p>メールを送信しました。</p>

<?php endif; ?>

ほぼこちらのサイトを参考にさせて頂きました。

参考サイト
- PHP: HTTP コンテキストオプション - Manual

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

PHPでRSSを作成

rdf拡張子のRSSを表示させる場合は以下の行が書かれた「.htaccess」を作成して、表示させたいrdfのディレクトリに置いてください。

「.htaccess」を作成させる場合はサーバーにアップしてからリネームすると「.」がついたファイルを作成できます。

.htaccess

AddType application/xml .rdf

SimpleXMLElementを使う事で、簡単にRSSを作成できます。
今回は作成したRSSをすぐに表示させていますが、一度ファイルとして保存したものを表示する方法でもいいと思います。
表示されない場合はhtmlspecialchars()で文字をエスケープしてから表示してみてください。
myblog.rdfを保存する場合は、サーバーの公開ディレクトリ直下にrssフォルダを作成してください。

rss.php

<?php

    try{

        $RSS = <<<EOT
<?xml version="1.0" encoding="UTF-8"?>
    <rss version="2.0">
        <channel>
            <language>ja</language>
        </channel>
    </rss>
EOT;

        $rssFileName = 'myblog.rdf';

        $XML = new SimpleXMLElement($RSS);
        $XML->channel->addChild('title', "ブログタイトル!");
        $XML->channel->addChild('link', 'http://' . $_SERVER['HTTP_HOST'] . '/rss/' . $rssFileName);
        $XML->channel->addChild('description', "ブログの更新情報です");

        $item = $XML->channel->addChild('item');
        $item->addChild('title', "記事タイトル");
        $item->addChild('link', 'http://' . $_SERVER['HTTP_HOST'] . "/page/mypage.html");
        $item->addChild('category', "カテゴリ");
        $item->addChild('description', "記事についての説明");
        $item->addChild('content', "記事の中身");
        $item->addChild('date', date('Y-m-d H:i:s'));


        header('Content-Type: text/xml');
        ob_end_clean();
        echo $XML->asXML();

        $file = fopen($_SERVER['DOCUMENT_ROOT'] . '/rss/' . $rssFileName, "w");
        fwrite($file, $XML->asXML());
        fclose($file);

    }catch ( Exception $e ) {
        // var_dump($e->getMessage());
    }


?>

ポイントとしてはob_end_cleanを使用することで、作成したRSSを直接表示させることが出来ます。

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

Node.jsでCSVからPHPに雑に変換してみる

WordPressのリプレイスもどき案件で大量(1,000件以上)のリダイレクトをすることになりそうなので、後の自分のダメージを減らすべく、準備がてらなるべく楽にリダイレクト出来る方法を考えました。

表題の通り 雑に 書いています。取り敢えず目的を果たす為だけにつくりました。

達成したいこと

  • 大量のリダイレクトの処理の手間を減らしたい。
    • 目視で1件ずつは勘弁…
  • 本番・開発・ローカルでファイルを共有出来る状態にしておきたい。
    • サーバーの仕様に影響される .htaccess は本番・開発・ローカルで共有したくない。(共有出来ない可能性がある。)
  • 自分以外の人もリダイレクト元とリダイレクト先の情報が一度に確認出来る状態にしておきたい。
    • プラグインを利用した場合、管理画面から1件ずつ確認するのが面倒臭そう。間違いに気付きにくい。
    • GoogleDriveなどで表にしておいて、必要な情報のみ抜き出して編集・閲覧出来る状態にしておけば、間違いに気付きやすくなる。

考えた方法

リダイレクト元とリダイレクト先のURLを記載したCSVファイルを作り、リダイレクト用のPHPに変換し、header('Location:...') を利用してリダイレクト。

今回はリダイレクトの条件の部分の変換を行いました。( header('Location... を書いてある別ファイルにincludeする前提)

プラグインを使用しなかった理由

  • プラグインによっては更新が止まっているものがある(アップデート後に不具合を起こす可能性がある)。
  • リダイレクトの設定が .htaccess に吐き出されるプラグインは避けたい。
    • 本番・開発・ローカルで .htaccess を使い回すことは避けたい。

前提条件

  • Node.js をインストール済みであること

使うもの

準備

パッケージをインストール

yarn add csv -D

若しくは

npm i csv -D

csvファイルと変換先の空のファイルを用意

csv

  • title:ページのタイトル
  • old:リダイレクト元のドメインより後のURL
  • new:リダイレクト先のドメインより後のURL
CSVのデータ
title,old,new
Contact,contact,sample-page
りだいれくとのてすと。さんぷるページに移動,19,sample-page
りだいれくとてすと2。プライバシーポリシーにいどう,21,privacy-policy

空のファイル

中身は書かずに hoge.php で保存

スクリプトを書く

convert-csv.js で保存

変換用スクリプト
/**
 * csvからリダイレクト用のPHPに変換するスクリプト
 */
const fs = require('fs');
const csv = require('csv');


/**
 * データをパースする
 */
const parser = csv.parse( { columns: true }, ( error, data ) => {

  if ( error ) {
    console.error(error);
    return;
  }

  /**
   * データからリダイレクト元とリダイレクト先のURLのみ取り出した配列を作成
   */
  const redirectUrlArray = data.map((obj) => {
    const oldUrl = obj['old'];
    const newUrl = obj['new'];
    return { oldUrl, newUrl };
  });

  /**
   * リダイレクト元とリダイレクト先の配列を元にPHPのswitch文の中身を作成
   */
  const arrayText = redirectUrlArray.map((obj) => {
    return `    case home_url('/').'${obj['oldUrl']}/':\n      $redirectUrl = home_url('/').'${obj['newUrl']}/';\n      break;\n`;
  });


  /**
   * テキストに変換
   */
  const outText = arrayText.join(',').replace(/,/g, '');

  /**
   * PHPファイルの中身
   */
  const outputData = `<?php\n  switch ($url) {\n${outText}\n  }\n?>`;

  /**
   * ファイルに書き出し
   */
  fs.writeFile(__dirname + 'hoge.phpのファイルパス', outputData, (error) => {

    if ( error ) {
      console.error(error);
      return;
    }
    console.log(outputData);
    console.log('変換完了');

  });

});


/**
 * ファイルの読み込み
 */
fs.createReadStream(__dirname + 'CSVデータのファイルパス').pipe(parser);

実行

convert-csv.js を保存したディレクトリで以下を実行

node convert-csv.js

実行結果

<?php
  switch ($url) {
    case home_url('/').'contact/':
      $redirectUrl = home_url('/').'sample-page/';
      break;
    case home_url('/').'19/':
      $redirectUrl = home_url('/').'sample-page/';
      break;
    case home_url('/').'21/':
      $redirectUrl = home_url('/').'privacy-policy/';
      break;

  }
?>

最後の break; の後に改行が入りますが動作に影響は無いので無視で・・・

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

我流VRMMOゲーム制作法(要点まとめ)

VRMMOゲームが作りたい!

私はVRMMOゲームを制作しています。
現在は仕様を練っている所です。

今回の記事が、私と同様VRMMOゲームを作ろうとする人の役に立つ事を願います。

制作環境

まず、ゲーム制作環境ですが、Unityにて開発、steamへアップロードを想定しています。
これは、OpenVR SDKやsteamVR pluginを初めとした外部技術導入の容易さからです。

以下に私の使用する外部技術を挙げます。

OpenVR SDK:UnityゲームをVR対応にする為に用います。情報が少ないです。

steamVR Plugin:ゲームをVR対応にする為に用います。こちらはカメラや各種コントローラ入力を扱います。

steamworks SDK,API:課金やアップロードなどを扱います。クライアント・自分のサーバ・steam WEB APIサーバでやり取りします。

随時記事を更新作成します。

ログイン

次に、ログイン機能についてです。

ログインにおいてはクライアント、サーバ間のやり取りが必要となります。
参考までに、

クライアントから、IDとパスワード、アバター情報をサーバに送信します。

VRM-FBX-JSONは相互変換可能です。アバター情報をJSON形式化します。

  1. クライアント:Unity及びPHPを用いてテキストデータ及びJSON形式データをHTTPにて送信

  2. サーバ:nginxにてテキストデータを取得、PHPを介してテキストデータをMySQLへ格納
    2.1 PHPにてアバターデータを取得、PHPを介してJSON形式データをMySQLへ格納

3.サーバ内でデータを照合します。ハッシュ化された値が正しいか確認。暗号化はダメです。復号されてしまうので。

4.データが正しい場合、PHPを介してサーバからクライアントへ照合完了を伝え、ログイン完了となります。

情報照合方法は改めて検討します。

また、細かな手続きについては都度記事を更新作成します。

アバター生成

JsonUtilityを用いて、MySQLから取り出したJSONをアバターに復元します。

90fpsの維持

1.クライアントは、Unity,C++を用いて、常時アバターの位置情報とアクション内容情報をJSON形式でUDPにてサーバに送信します。

同時に、サーバから情報を受け取った場合、空間情報を全て更新します。

2.サーバは、クライアントから受け取ったJSON情報を元に、各々、位置、アクション情報を更新します。

その後、更新したJSON情報をサーバ間で同期します。

最後に、同期された情報をクライアントへUDPにてJSON情報を送信します。

3.クライアントは受け取ったJSONデータを元に空間を再構成します。

これを1秒間に180回行います。UDP通信なので半分の通信は失敗する想定です。

細かな手続きは随時記事を作成更新します。

実験してみないと分からない事が多いです。

最後に

VRMMOゲームのシステムについて考えてみました。

一緒に作りたいという方は連絡下さい。作りましょう。

ご意見のある方がいらっしゃいましたら、アドバイスを下さい。

分からない事が多い為、情報提供頂けると助かります。

よろしくお願いします。

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

我流VRMMOゲーム制作法(要点)

VRMMOゲームが作りたい!

私はVRMMOゲームを制作しています。
現在は仕様を練っている所です。

今回の記事が、私と同様VRMMOゲームを作ろうとする人の役に立つ事を願います。

制作環境

まず、ゲーム制作環境ですが、Unityにて開発、steamへアップロードを想定しています。
これは、OpenVR SDKやsteamVR pluginを初めとした外部技術導入の容易さからです。

以下に私の使用する外部技術を挙げます。

OpenVR SDK:UnityゲームをVR対応にする為に用います。情報が少ないです。

steamVR Plugin:ゲームをVR対応にする為に用います。こちらはカメラや各種コントローラ入力を扱います。

steamworks SDK,API:課金やアップロードなどを扱います。クライアント・自分のサーバ・steam WEB APIサーバでやり取りします。

随時記事を更新作成します。

ログイン

次に、ログイン機能についてです。

ログインにおいてはクライアント、サーバ間のやり取りが必要となります。
参考までに、

クライアントから、IDとパスワード、アバター情報をサーバに送信します。

VRM-FBX-JSONは相互変換可能です。アバター情報をJSON形式化します。

  1. クライアント:Unity及びPHPを用いてテキストデータ及びJSON形式データをHTTPにて送信

  2. サーバ:nginxにてテキストデータを取得、PHPを介してテキストデータをMySQLへ格納
    2.1 PHPにてアバターデータを取得、PHPを介してJSON形式データをMySQLへ格納

3.サーバ内でデータを照合します。ハッシュ化された値が正しいか確認。暗号化はダメです。復号されてしまうので。

4.データが正しい場合、PHPを介してサーバからクライアントへ照合完了を伝え、ログイン完了となります。

情報照合方法は改めて検討します。

また、細かな手続きについては都度記事を更新作成します。

アバター生成

JsonUtilityを用いて、MySQLから取り出したJSONをアバターに復元します。

90fpsの維持

1.クライアントは、Unity,C++を用いて、常時アバターの位置情報とアクション内容情報をJSON形式でUDPにてサーバに送信します。

同時に、サーバから情報を受け取った場合、空間情報を全て更新します。

2.サーバは、クライアントから受け取ったJSON情報を元に、各々、位置、アクション情報を更新します。

その後、更新したJSON情報をサーバ間で同期します。

最後に、同期された情報をクライアントへUDPにてJSON情報を送信します。

3.クライアントは受け取ったJSONデータを元に空間を再構成します。

これを1秒間に180回行います。UDP通信なので半分の通信は失敗する想定です。

細かな手続きは随時記事を作成更新します。

実験してみないと分からない事が多いです。

最後に

VRMMOゲームのシステムについて考えてみました。

一緒に作りたいという方は連絡下さい。作りましょう。

ご意見のある方がいらっしゃいましたら、アドバイスを下さい。

分からない事が多い為、情報提供頂けると助かります。

よろしくお願いします。

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

Laravel ide-helperでモデルのIDE保管用コメントを作成する

LaravelでIDE補完されやすくするではide-helperの導入とLaravelの基本クラスのIDE保管用ファイルの作成方法を紹介しました。

今回はide-helperを使用してEloquentクラスを継承したモデルのプロパティなどをテーブルから作成してくれる機能を紹介します。

使用するテーブルとモデルはLaravelでマイグレーションしてモデルファイルを作成するの記事でご紹介したshopsテーブル/Shopモデルを使用します。

doctrine/dbalのインストール

ide-helperでモデルにコメントを入れる機能を使用するにはdoctrine/dbalの追加が必要になるので下記コマンドでインストールします。

composer require --dev doctrine/dbal

コマンドの実行

インストールしたら下記コマンドを実行すると書くモデルファイルに対してIDE補完用のコメントが追加されます。

php artisan ide-helper:models

コマンドを実行すると上書きしていいか聞かれるので、yesと入力してenterを押下します。

するとこのような何の記述もないモデルファイルが

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

class Shop extends Model
{
    //
}

このようになります。

<?php

namespace App;

use Illuminate\Database\Eloquent\Model;

/**
 * App\Shop
 *
 * @property int $id
 * @property string|null $name 店舗名
 * @property string|null $sub_name 支店名
 * @property \Illuminate\Support\Carbon|null $created_at
 * @property \Illuminate\Support\Carbon|null $updated_at
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Shop newModelQuery()
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Shop newQuery()
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Shop query()
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Shop whereCreatedAt($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Shop whereId($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Shop whereName($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Shop whereSubName($value)
 * @method static \Illuminate\Database\Eloquent\Builder|\App\Shop whereUpdatedAt($value)
 * @mixin \Eloquent
 */
class Shop extends Model
{
    //
}

もしプロジェクトルート/app配下以外にモデルファイルを作成している場合(例えばapp/Models/Shop.phpみたいな場合は)

php artisan ide-helper:models App\\Models\\Shop

のようにnamespaceを指定してあげると反映されます。

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

PHPでデータベース接続(PDO)

PHPでデータベース接続する時、PDO周りは不明な用語が沢山出てきて混乱しがちな為、
単語や情報を一つずつ整理してロジックを組み立てる必要がある。

データベース接続の流れ

データベースの接続 → データベースの操作 → データベースとの接続終了
という流れが基本的な鉄則。

例えるなら、
本棚から必要な本を見つけ手に取る(接続)
本の中から必要な情報を探す(操作)
本を閉じ、本棚にしまう(接続終了)
と行った所。

書き方 判例

接続方法自体は色々あるが現在は、PDO(PHP Data Object)が主流。

下記判例を示すと、

php
<?php
//まず登録項目3点を変数化する。
$dsn = 'mysql:dbname=指定のテーブル;host=指定のホスト名;charset=utf8';
$user ='RDBMS登録のユーザー名(rootとか)';
$password ='RDBMS登録のユーザーパスワード(rootとか)';

//例外処理
try{
   $dbh = new PDO($dsn, $user, $password);  //ここが接続の文
   $dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
   $sql = "SELECT * FROM recipes";
   $stmt = $dbh->query($sql);
   $result = $stmt->fetchAll(PDO::FETCH_ASSOC);
   echo $result;
   $dbh = null;
}catch(Exception $e){
   echo"接続失敗:". htmlspecialchars($e->getMessage(),ENT_QUOTES, 'UTF-8') . "<br>";
   die();
}

?>

こんな所でしょうか?
初心者がいきなりこれを見ても、は?って感じになりますよね。
いろんな部分が、は?って感じですよね。
何回写経した所で、一つ一つの箇所が理解出来ない事には、このPDO周りの部分は毎回大きく時間が取られてしまいます。

そこで一つ一つパーツごとに切り分けて、ロジックを噛み砕いていかなくてはいけません。

・new PDO・・・PDOで接続。newはそのまま「新たに」って意味で、ここはもうそういう書き方をしないといけないと思うようにしましょう。
      new PDOの後に、接続情報やユーザー名、パスワードなどを指定して準備していく。
      ここまでの固まりを「$dbh」という変数に格納する。
今後データベースの機能を使う場合には、この変数「$dbh」を指定する。

・$dbh->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
・・・生成したPDOオブジェクトに対して、setAttribute()メソッドで設定を行い、
      データベース接続の設定(エラーモードの設定)をこの行でやっている。
      setAttribute()メソッドは、データベース接続時の設定や、SQL文実行時の挙動など、
      データベースハンドルの属性を変更するためのメソッド。

$stmt = $dbh->query($sql);
   ・・・①$dbhはデータベースの接続を設定した変数
    ②queryは問い合わせ、質問するといったイメージ
    ③$sqlはSQL文の内容
    という流れから、この文は、SQL文を実行して結果を問い合わせるという意味が入っている。
    ->query()とする事で、PDOの機能の問い合わせを実行する事が出来た。

$result = $stmt->fetchAll(PDO::FETCH_ASSOC);
    ・・・SQL文の実行結果をカラム名をつけた配列として取り出す。
     配列として全て取り出す命令はfetchAll()という関数。
     PDO::FETCH_ASSOCは、実行結果をつけた配列として返す。
     

・$e->getMessage()
 ・・・catch時にExceptionを代入する変数$eを用意する。Exceptionは例外という意味。
    $eの中にあるメッセージを取得する命令getMessage()は、$dbhで指定した時と同様に、
    ->(アロー演算子)で指定する。
    $e->getMessage()とすれば、エラー発生時のメッセージを取得できる。

こうやって一つ一つ要約していくと、順序立てて処理が進んでいる事が分かる。

まずデータベース接続する。
エラー設定をする。
SQL文を発行する準備をする。
SQL文を発行して問い合わせる。
SQL文の実行結果を取り出す。
データベース接続を切断する。

といった流れとして、翻訳が成り立つ。
PDOstatementの所はもう少し詳細が欲しい所なので、それはまた次の機会にまとめる。

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

YouTubeのチャンネルを分析するサービスで利用したYouTube Data APIについて

新たにYouTubeのチャンネルを分析してチャンネルの登録者数、総再生回数を取得して表示する他、動画の再生数の多い順に表示するWebサービスを作ったので、その中で利用したYouTube Data APIの関数について解説します。

作ったサービスはこちらになります。
Bestube -ベスチューブ-
https://www.bestube.net/
スクリーンショット 2019-07-22 20.01.38.png

YouTubeのAPIは複数用意されていて、訪問者が視聴した時間、視聴者の離脱率など主に自分の管理している動画に関する情報を取得するAPIであるYouTube Analytics API、YouTube Reporting APIと、認証なしでYouTube上の動画やチャンネルの情報を取得できるYouTube Data APIがあります。

BestubeではYouTube Data APIを利用してチャンネル情報や動画情報を取得しています。

具体的には、まず、Google Developer Consoleでアカウント登録をしてプロジェクトを作成します。
その上でプロジェクトのYouTube Data APIを有効化し、認証キーを作成します。
認証キーを取得したら、Google API LibrariesをGitHubから取得してインストールします。
言語はそれぞれ適切なものを利用するものとしますが、BestubeはPHPで書かれていますので、こちら(https://github.com/googleapis/google-api-php-client?hl=ja) からダウンロードしました。

Bestubeではチャンネル情報を取得する時に以下の処理をしています。

1.チャンネルのIDからチャンネルの情報(紹介文、サムネイル、総再生回数など)を取得する。→Channelsのlistメソッドを呼ぶ(https://developers.google.com/youtube/v3/getting-started) 。

2.チャンネルに登録されている動画を検索し、チャンネルに投稿されている動画のIDを全て取得する。→Searchのlistメソッドを呼ぶ(https://developers.google.com/youtube/v3/guides/implementation/search) 。

3.取得した動画のID(複数を同時に取得可)から動画の情報(統計情報やサムネイルなど)を取得する。 →Videosのlistメソッドで取得(https://developers.google.com/youtube/v3/guides/implementation/videos) 。

この三つの過程によってYouTubeチャンネルの動画人気ランキングを作成します。一度にこれらの情報を取得できれば楽なのですが、チャンネルの情報に加えてチャンネルに投稿された動画の詳細情報についても掲載する必要があるので自分の知る限りですとこれらの処理が必要になってくると思われます。

YouTube APIは定められたクォータ(利用可能なAPIのコール制限)内でしか使用できないきまりになっています。このチャンネル情報の取得では必要となるクォータの量がかなり多いので、それをどうにか圧縮することが今後の課題です。

改善点が見つかったらまた追加いたします。

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