カテゴリーアーカイブ PHP

著者:杉浦

【PHP】ファイルの中身からファイル形式を識別する

 webサービスではユーザがサーバにファイルを送ることはよくあります。送られたファイルの中身を扱うこともよくあります。想定していない振る舞いをするファイルを扱った際はバグに繋がりやすく、時にセキュリティの問題も引き起こします。ファイル形式の識別と識別結果による条件分岐は必要になります。
 ファイル形式の識別は簡易な方法がいくつかあります。例えば、ファイル名末尾にある拡張子から読み取れます。セキュリティ的にはとても信用できませんがファイル名のみで判別というのはとても高速で簡単です。例えば、MIMEタイプで大別できます。とはいえまだ偽装は簡単です。ファイルの中身からファイル形式を読み取る方法はこれらよりいくらか頑強な方法です。
 MIME タイプ (IANA メディアタイプ) – HTTP | MDN
 ファイルの中身の先頭にはマジックナンバーと呼ばれるバイナリ形式の署名が入っています。形式によってはテキストエディタで無理やり開くと文字列で一部が見えます。下の画像の”臼NG”のあたりです。


 ファイル形式とマジックナンバーは次のサイトらにまとめられています。
File Signatures
File Signature Database:
 これと読み取ったファイルの中身を突き合わせることでファイル形式を識別します。PNG形式ならば次の通り、16進コードで表して” 89 50 4E 47 0D 0A 1A 0A”となっています。

 PHPならば次の様に検証できます。

function isPng($content){
    $png_sig = "\x89\x50\x4e\x47\x0d\x0a\x1a\x0a";
    return strpos($content, $png_sig) === 0;
}

 ダブルクォーテーションでくくった文字列はエスケープシーケンスが使え、\xhhは”16進コードで hh の文字”を表します。
PHP: エスケープシーケンス – Manual
 先ほど得られた16進コードによるファイル先頭マジックナンバーをエスケープシーケンスによるも文字列で表し、strposで先頭からマジックナンバーが現れるかを確かめます。
PHP: strpos – Manual
 これでファイル形式を識別できます。先頭が正しくともさらに続きの部分で攻撃の余地があるかもしれませんがノーガードよりは随分ましになります。

 ファイルのバイナリはLinuxコマンドのod -h [ファイル名] | less -Fが読みやすかったです。

  • この記事いいね! (1)
asaba 著者:asaba

【zendframework】行の要素を一行ずつ巡回する方法

ここ最近phpでsqlに触れる機会が少しあったので、せっかくなので配列に一行ずつアクセスする

処理を勉強がてらブログに残していきます。

まずテーブルを指定して、行を配列の要素として返すにはtoArray()メソッドを使います。

toArray()メソッドは、テーブルにある一つの行を配列の要素として持たせることができるメソッドで

カラムと値はkey=>valueの形で連想配列として扱われます。

 

</pre>
$Tables = new Tables();
$rowset = $Tables->fetchAll();

$rowsetArray = $rowset->toArray();

$rowCount = 1;
foreach ($rowsetArray as $rowArray) {
echo "row #$rowCount:\n";
foreach ($rowArray as $column => $value) {
echo "\t$column => $value\n";
}
++$rowCount;
echo "\n";
}
<pre>

 

一つ目のforeachで行を一つずつ見ていき、ネストされたforeachでは行のカラムの要素を一つずつ

見て一つずつ出力しているのが分かります。

 

これを上手く使えば、全列にアクセスして該当した値に対して指定した数値以下の値を書き換える・削除する

といった柔軟な動きを降り入れることができるのでキホンとして覚えておきたいですね。

 

もう少しフレームワークの動きとsqlの基礎が分かってきたらもう少し掘り下げていじってみたいと思います。

  • この記事いいね! (0)
takahashi 著者:takahashi

PHPは”オワコン”?いやいや…

PHPよりも○○の方がいい、ネット上ではそんな話もちらほら見かけます。

PHPはもう古いから他の言語に乗り換えた方がいい、とかですね。

そんな中、最近こんな記事を見つけました。

PHPはもうダメだ、PHP万歳!- POSTD

“PHPはもうダメだ”といったブログの投稿が、登場し始めたのは2011年のようです(これより古いものを見つけたら、お知らせください)。Mediumや、mushroomsのように突然出現したcoding bootcampsを探し回れば、その唯一の共通点は、みんながPHPを嫌っているか、あるいは単に無視しているかです。どうやら、法外な値段のコーヒーを飲みながら、油まみれのヒゲと皮肉たっぷりのTシャツと一緒に、PHPでコーディングするのは不可能のようです。

ばかな!
もうたくさんです。反PHPのエコーチェンバー現象のせいで、疑わしいビジネス上の決断を下そうとしている創設者に私はいつも話しかけています。
これが現実です。2018年現在、Webサイトの約80パーセントがPHPが使用している
PHPは、なんだかんだ言っても、それほど廃れていないと思います。

https://postd.cc/php-is-dead-viva-le-php/

こちらの記事でも突っ込まれていますが、実際PHPはいまだによく使われている言語であるという話は僕も同感です。

もし使われていなかったら、Laravelのような優秀なフレームワークの開発がどうして継続されるでしょうか。

それに、PHPは本家も定期的にアップデートしている言語ですし、オブジェクト指向もサポートされていますし、いまだにひけをとらない仕様の言語だとも思います。

パッケージマネージャーのComposerもありますしね。

昔からWebサーバーとの親和性もいいので、入門にも是非お勧めしたい言語でもあります。

…とはいえ、自分は必ずしもPHPが100%良いとも考えていなくて、ディープランニングとかにも強そうなPythonとかもちょっと触れるようになりたいなぁ…とかもちょっと考えちゃいますけどね…w

とりあえず、もうしばらくはPHPでプログラミングのノウハウをためてから、是非他の言語もチャレンジしたいですね。







# サーバーサイドもクライアントサイドもなんでもできてしまうJavascriptが実は一番すごいのかもしれない
AI(人工知能)の開発に適したプログラミング言語ランキング8選

  • この記事いいね! (0)
asaba 著者:asaba

【php】phpのIDEの充実ぶりがすごい

久々にphpをいじる機会が訪れました。なのでここ最近はもっぱらphpのコードを見たり直接いじったりしています。

自分も学生時代にphpをいじったことがあるのですが、その時は確か秀丸?とかサクラエディタを使っていたのですが

今のphpの開発環境って結構進んでいるんですね。。。

なんせhtmlを開いたり閉じたりしながらエラーを確認していたので、その時の開発の効率の悪さといったら

目も当てられない、悪く言うと黒歴史です()。

 

例えばphpstormはgitとも連携しているしSQL文もきっちり識別してくれます。

javaでいうandroidStudioのポジションですね。家でちょこっと試してみたい・開発したい時もこれを

使って試すなんてことも簡単なので初心者でも他のエディタから移住してきた人でも親しみやすそうですね。

 

JEditはプラグインが充実しているので自分でお好みの機能をつけて自分色のeditに染めてしまう

こともできそうです。

うーん、こいつらいいなと思っていたのですが今僕が使っているatomでも両方できるやんけと思い出したので

シビアなバックエンド開発にならない限りはこのまま変えずに頑張っていきます。

 

 

  • この記事いいね! (0)
著者:杉浦

【PHP】composerを使ったライセンスチェック

 composerはPHPのパッケージインストーラでその中にはいくつか機能があります。機能の一覧はcomposer listで確認できます。composer licensesはその中の機能の一つでcomposerでインストールされているパッケージ全ての名前、バージョン、ライセンス種類を表示してくれます。
 
 ライセンスは深く気にするべき時、しなくていい時があります。どこの誰にでもソースコード込みで公開するOSSの開発時は派生だろうがなんだろうが元のライセンスを継承して完全公開すれば大体OKですが、商用の場合そうもいきません。いくつか避けるべきライセンスがあります。
 避けておいた方が無難なライセンスはGPL系、特にAGPLです。AGPLはAFFERO GENERAL PUBLIC LICENSEの略です。
 GNUアフェロ一般公衆ライセンス – GNUプロジェクト – フリーソフトウェアファウンデーション
 AGPLは次の通りのことをプログラムに要求します。

GNUアフェロ一般公衆ライセンスは通常のGNU GPLバージョン3を改変したバージョンです。これには一つ要求が加わっています。サーバで改変したプログラムを動かし、そこでそのプログラムとほかのユーザに通信させる場合、サーバはユーザにそこで動いている改変バージョンに対応するソースコードのダウンロードも許可しなければいけない、というものです。

 どこまでが改変だとかの解釈は理解していませんが(継承した時点でアウト?)、AGPLのプログラムを含むプログラムを動かした場合、そこに正規でアクセスしたユーザはソースコードも手に入れられなければならない、という状況になりそうです。商用ということは扱うものがものですから悪意のあるユーザへの対策は必須です。ソースコードの公開はセキュリティホールの発見を容易にします。あるいは見つかるはずのなかった穴を見つけさせます(マジックナンバーで書かれた何かしらとか。設定ファイルを介するプログラムを組んでおけばそれだけで回避可能ですが)。
 composerのライセンスチェック機能を使うと、こういった問題を容易に回避できます。やることはシンプルで次のようにcomposer licensesの結果にgrepをかけるだけです。

composer licenses | grep -v -P ^\(?=.*[^,]\(MIT\|BSD-3-Clause\)[^,]\)


 安全安心な許容できるライセンスによるホワイトリストがよいと思います。

  • この記事いいね! (1)
著者:杉浦

値オブジェクトを作った方が良い時悪い時

 値オブジェクトはエリック・エヴァンスのドメイン駆動設計 | Eric Evans, 和智右桂, 牧野祐子, 今関剛 | 工学 | Kindleストア | Amazonの中で次の様に述べられています。

あるオブジェクトが、ドメインにおける記述的な側面を表現し、概念的な同一性を持たない場合、そういうオブジェクトは、値オブジェクトと呼ばれる。値オブジェクトがインスタンス化される際に表現しようとするのは、何であるかだけが問題となり、誰であるか、あるいはどれであるかは問われないような設計の要素である。

Eric Evans. エリック・エヴァンスのドメイン駆動設計 (Kindle の位置No.2480-2483). 翔泳社. Kindle 版.

 乱暴な言い方をすれば任意の型で定義されたインスタンスを実現するオブジェクトです。例えば、PHPならば次のような実装ができます。

class GeoPoint
{
    private $lat;// 緯度
    private $lng;// 経度
    
    /**
     * GeoPoint constructor.
     * @param $lat
     * @param $lng
     */
    public function __construct($lat, $lng)
    {
        $this->setLat($lat);
        $this->setLng($lng);
    }
    
    /**
     * privateプロパティを読み取り可能にする.
     * @param $name
     * @return mixed
     */
    public function __get($name)
    {
        return $this->$name;
    }

    /**
     * 一部のprivateプロパティを書き込み可能にする.
     * @param $name
     * @param $value
     * @return mixed
     */
    public function __set($name, $value)
    {
        $setter = 'set'.ucfirst(camel_case($name));

        return $this->$setter($value);
    }

    /**
     * privateプロパティにissetできるようにする.
     * @param $name
     * @return bool
     */
    public function __isset($name)
    {
        return isset($this->$name);
    }

    /**
     * 存在しないメソッドが呼ばれたらnullを返す.
     * @param $methodName
     * @param $arguments
     * @return null
     */
    public function __call($methodName, $arguments)
    {
        return null;
    }

    /**
     * __setで呼ばれるprivateプロパティへのsetter
     * @param $value
     */
    private function setLat($value)
    {
        if (-90 < $value && $value < 90) {
            $this->lat = $value;
        }
    }

    /**
     * __setで呼ばれるprivateプロパティへのsetter
     * @param $value
     */
    private function setLng($value)
    {
        if (-180 < $value && $value < 180) {
            $this->lng = $value;
        }
    }
}

 上コードならば緯度経度で地点を表現するオブジェクトです。インスタンス化時、プロパティ変更時に必ずsetHoge()を通し、setHoge()の中で不適正な値が代入されることを防ぎます。例ならば緯度は必ず-90度から90度の範囲であるし、経度は-180度から180度の範囲と限っています。setに失敗したら何も起きない作りですが、もっと厳格に作って、失敗したら即座に例外をthrowするのも全然ありです。
 値オブジェクトは極端なカプセル化の実現です。上記コードの様に好き勝手ルールを増やしても外からはルールは変えられず、見えません。必要なプロパティだけが見えます(キャストとか便利コンストラクタとかもありな気がします)。
 上記の例は緯度経度のみのざっとした作りですが、プログラムで扱う領域に複雑な概念や特殊な値の振る舞いがある程、値オブジェクトは強力になります。
 値オブジェクトを導入していないコードで値オブジェクトを導入した方が見通しがよくなる時、よくならない時があります。よくならない時は単純な種類のデータを扱っている時です。上の例にある通り、ちょっとしたものでも数十行コードが増えます。増えた分読みにくくなります。よくなる時は色々ですが、同じキーセットの配列やオブジェクトが至る所で現れるコードはよくなりやすいです。そういった時は特定のキー名で同じ概念を表現していることが多いです($hoge[‘lat’], $hoge[‘lng’]で検索すると恐ろしい数が出たり)。そういったキーをそのままプロパティにしてプロパティに適したルールをつけるだけで安全で読みやすいコードになります。

  • この記事いいね! (1)
著者:杉浦

【PHP】のスターリンソートがけっこうそれっぽい

 スターリンソートとはジョークソートアルゴリズムの一つです。

I came up with asingle pass O(n) sort algorithm I call StalinSort.
You iterate down the list of elements checking if they’re in order.
Any element which is out of order is eliminated.
At the end you have asorted list.
gustavo-depaula/stalin-sort: Add a stalin sort algorithm in any language you like ❣️ if you like give us a ⭐️

 スターリンソートは、要素を先頭から順番に見ていき、ソートされていない要素を発見する度に粛清することによって昇順ソートを実現します。全要素を一つずつ見るだけなので計算量はO(n)であり、高速です。

3, 6, 2, 1, 7, 10, 1, 10
↓
3, 6,       7, 10,    10
↓
3, 6, 7, 10, 10

 アルゴリズム完了時に昇順で要素が並んでいるので昇順ソートと言い張れます。入力時から要素が減っていようと昇順ソートです。(ソートの要件満たしていないし実際にはフィルターに分類されます)
 多くの言語は配列を詰めていくのでスターリンソート完了時には粛清された要素なんて最初からいなかったと思わされます。

 ですがPHPはそうなりません。

 PHPの配列は順番づけられたマップに過ぎず、キーと値はがっちり結びついており、配列が詰められることはありません。そのため次の様なことにもなります。

 紐づいた値に基づいて複数の名前が消されました。消された要素は戻ってきません。

  • この記事いいね! (0)
著者:杉浦

【Laravel】データベースと無関係のEloquentっぽいモデルを作るためのFluentクラス

 LaravelはEloquentクラスにモデルをまとめています。Eloquentはデータベース中のテーブルに対応して扱われることを前提としたORMです。
Eloquent:利用の開始 5.8 Laravel
 webサービスにおいてモデルが欲しい時は大体、対応したテーブルを用意するのですが、時にはデータベースに関係なくモデルを作りたい時があります。具体的には別のサービスで吐き出されたファイルの中身を扱う時などです。そういった時に手製のクラスファイルを作成するのも一つの手ですが、何かしたいことが増える度に簡単なことでも一々コードを書く必要があります。何かしら継承なりuseしたいですがEloquentを継承するのは危険です。誤った呼び出し一つで存在しない場所を参照するSQLを投げるがPHP的には正しいコードが出来上がります。
 FluentはLaravelの\Illuminate\Support\Fluentに位置しているEloquentの様なプロパティ制御とjson、array扱いの要素(ArrayAccess, Arrayable, Jsonable, JsonSerializableのinterfaceを満たしている)を持った素朴なクラスです。Laravel内部で扱われているのが基本でドキュメントなしのクラスです(Laravel4とかの頃のモデルクラスっぽい?)。Fluentのコンストラクタは次の様になっており、適宜new Fluent(パラメータ配列)をすることでデータベースに関係ないEloquentライクなモデル実体を扱えます。

    /**
     * Create a new fluent instance.
     *
     * @param  array|object  $attributes
     * @return void
     */
    public function __construct($attributes = [])
    {
        foreach ($attributes as $key => $value) {
            $this->attributes[$key] = $value;
        }
    }

 継承して、そのクラスをnewしただけでインスタンスにさせたいこと、インスタンスから知りたいことの設定が完了します。クラスだけ作って何も中身がないのに自在に動く様はEloquentを彷彿とさせます。
 簡単にnewする対象を探索する処理を入れるとなお便利です。例えば次の様なstaticメソッドを生やすことでなお扱いやすくなります。

    /**
     * ファイル名で探す。
     * @param  string $filename
     * @return mixed
     */
    public static function find(string $filename)
    {
        $disk = Storage::disk('hoge_files');
        if(!$disk->exist($filename)){
            return null;
        }
        $meta_data = $disk->getMetadata($filename);
        $body_data = self::parse($disk->get($filename));
        
        return new self(array_merge($meta_data, $body_data);
    }

 バリデータを作ってコンストラクタ中で呼び出す様な仕組みを作るとプロパティに何があるのかきっちり決まり更に更に安全安心に使えます。

  • この記事いいね! (1)
著者:杉浦

【PHP】関数implodeの引数が類を見ないくらい自由だった話

 文字列の結合と分割はよく行われる操作であり、PHPにもそのための組み込み関数implode, explodeが用意されています。
PHP: implode – Manual
PHP: explode – Manual
 それぞれドキュメント上では次の様な呼び出し方が説明されています。

implode ( string $glue , array $pieces ) : string
implode ( array $pieces ) : string
explode ( string $delimiter , string $string [, int $limit = PHP_INT_MAX ] ) : array

 第一引数に区切り文字、第二引数に対象が入るのだな、と理解できます。しかしこのimplode実は次の様にも動きます。

 第二引数に対象、第一引数に区切り文字でも動きます。暗黙の内によしなにしてくれるのはPHPあるあるですが流石にこれは凄まじいです。ちなみにexplodeはダメです。公式で次の様に注意喚起されています。

注意:

歴史的理由により、implode()
はいずれのパラメータ順も受け入れることができますが、
explode() はそうできません。
string 引数の前に必ず
delimiter 引数がくるように確認する必要があります。

あまりにも自由すぎたのかPHP7.4から非推奨になります。RIP.
PHP: rfc:deprecations_php_7_4#implode_parameter_order_mix

  • この記事いいね! (1)
著者:杉浦

【Laravel】Duskのテストケースを楽に作るChrome拡張Laravel TestToolsの紹介

 DuskはLaravelと密にかかわっている自動ブラウザテストツールです。実際にブラウザを開いて、あるページへ移動できるか、そのページである操作はできるか、操作の結果は想定した通りか、といったテストを自動で行ってくれます。ブラウザを用いる以上しょうがないかもしれませんが実行時間が長いのが玉に瑕です。
Laravel Dusk 5.8 Laravel
 テストコードは例えば次の様に書けます。

    public function testBasicExample()
    {
        $user = factory(User::class)->create([
            'email' => 'taylor@laravel.com',
        ]);

        $this->browse(function ($browser) use ($user) {
            $browser->visit('/login')
                    ->type('email', $user->email)
                    ->type('password', 'secret')
                    ->press('Login')
                    ->assertPathIs('/home');
        });
    }
    /**
     * <a href="https://readouble.com/laravel/5.8/ja/dusk.html">Laravel Dusk 5.8 Laravel</a>から引用
     */

 テストユーザを作成。/loginへ訪れて、name=”email”のinputタグにテストユーザのemailを入力、name=”password”のinputタグに’secret’と入力、Loginと書かれたボタンを押し、押した後のページのアドレスが/homeであることを確かめるコードです。簡単に記述するために相当暗黙知が入っています。慣れれば楽なのですが、慣れるまで具体的にどこの何が何であれば期待した通りに動作するのか、少し戸惑います。Laravel TestToolsは操作の記述を楽にしてくれます。
Laravel TestTools – Chrome ウェブストア
 具体的に何をするかというと操作の記録とコード起こしです。次のgifの様に録画ボタンを押すと動作を記録します。

 書き起こされたコードをコピペするだけで操作分の記述完成です。これでtype()やpress()を記述する際にそう悩む必要がありません。後はassertで確かめるだけです。

  • この記事いいね! (1)