やったこと

webサービスを作るときに考えたことを垂れ流します

【CakePHP3】マイグレーションのDB変更が反映されない!

先日CakePHP3の「Migration機能」で、あるテーブルに変更を加えたんです。

以下のような感じで「tweet_type」というカラムをテーブルに追加する変更をやりました。

class AddTweetTypeProducts extends AbstractMigration
{
    public function change()
    {
      $table = $this->table('tweets');
      $table->addColumn('tweet_type', 'integer', ['default' => 1, 'null' => false,])
            ->update();

      $table = $this->table('draft_tweets');
      $table->addColumn('tweet_type', 'integer', ['default' => 1, 'null' => false,])
            ->update();
    }
}

上記をマイグレーションコマンドで実行すると、たしかにテーブルに新しくカラムが追加されます。

でも「Table->find」でデータを取得すると「tweet_type」のない古い状態のレコードが取得されてしまうんです・・。

これはどうもCakePHPのキャッシュに、古いテーブルのスキーマ情報が保存されてしまっていることが原因っぽいです。

「tmp/cache/models/」のディレクトリがありますよね。ここにあるファイルを全部削除して空にしてみたところ、新しいスキーマが反映されてちゃんと「tweet_type」のカラムを操作できるようになりました。

DBに変更を加えたら「models」のキャッシュを削除しなくてはいけない、こんな決まりがあるとは知りませんでした。

CakePHPはなかなか甘くないですね・・。

以上です・・。

ツイッターカードの画像が表示されないときはしばらく待つこと!

自分のサイトに「ツイッターカード」をセットすると、サイトをツイートしたときに「画像付き」で表示させることができます。

自分のサイトのツイッターカードがうまく機能しているかどうかは、この「カードバリデーター」にURLを入れてチェックすることができます。

https://cards-dev.twitter.com/validator

ときどきちゃんとツイッターカード情報を設定したつもりなのに、このチェッカーで調べると、なぜか画像がグレーになって表示されていないときがあります・・。

そういうときは、小一時間ほど待ってみましょう。

特になにもしていないのに、しばらく経つとなぜか画像が表示されるようになります。

特になにもしていないのに、しばらく経つとツイッターカードが正常に利用できるようになります。

そう、なにもしていなくても、じっと待っていれば時間が解決してくれるのです・・。

【CakePHP3】AWS SDK for PHPでS3サーバーにファイルをアップロード!

AWS SDK for PHP」というアマゾン公式ライブラリを使うと、PHPを使ってアマゾンのS3サーバーにファイルをアップロード・ダウンロードすることができます。

今回は「CakePHP3」でS3サーバーにファイルをアップロードする方法を説明します。


■「AWS SDK for PHP」のインストール
AWS SDK for PHPのインストールは「Composer」を使ってワンタッチでできます。
cakePHP3のディレクトリで以下のコマンドを打つとインストールされます。

  php composer.phar require aws/aws-sdk-php


■ファイルをアップロード
ファイルをアップロードするコードは以下のような感じです。
自分のディレクトリにあるファイル「hogege.jpg」を、S3サーバーにアップップロードしています。

use Aws\S3\S3Client;

public function initialize()
{
   $this->config = [
     's3' => [
       'key' => 'hogehogehogegege', //S3アクセスのためのキー
       'secret' => 'fugafugafugaga', //S3アクセスのためのシークレットキー
       'bucket' => 'image.hogege.com', //S3バケット名
     ]
   ];

   $this->s3 = S3Client::factory([
     'credentials' => [
       'key' => $this->config['s3']['key'],
       'secret' => $this->config['s3']['secret']
     ],
     'region' => 'ap-northeast-1', //リージョンは日本
     'version' => 'latest' //バケットのバージョニングは最新
   ]);
}

public function upload_img($post_id)
{
  //アップロードするファイルのパス
  $filepath = dirname(__FILE__)."/temp/hogege.jpg";

  //AWSに登録するオブジェクト・キー名
  $keyname ="hogege.jpg";

  //アップロード!
  try{
    $result = $this->s3->putObject([
        'Bucket'       => $this->config['s3']['bucket'],
        'Key'          => $keyname,
        'SourceFile'   => $filepath,
        'StorageClass' => 'REDUCED_REDUNDANCY' //低冗長化モードを指定
    ]);
  } catch (Exception $ex) {
    return false;
  }
  return true;
}


ちなみに、他のサイトにあるファイルをかっぱらってきてS3にアップロードする場合は、以下のような感じでできます。

ちゃんとMIMEタイプを指定してあげないといけないのがポイントです。これをしないとMIMEタイプが「application/octet-stream」でアップロードされてしまいます・・。

  //testes.jpgを取得する
  $img_data = file_get_contents("http://fugaga.com/testes.jpg");

  //mime typeを判別
  $finfo = finfo_open(FILEINFO_MIME_TYPE);
  $mime_type = finfo_buffer($finfo, $img_data);
  finfo_close($finfo);

  $keyname = 'testes.jpg';

  //S3にアップロード
  $result = $this->s3->putObject([
    'Bucket'       => $this->config['s3']['bucket'],
    'Key'          => $keyname,
    'Body'         => $img_data,
    'ContentType' => $mime_type,
    'StorageClass' => 'REDUCED_REDUNDANCY' //低冗長化モードを指定
  ]);

アマゾンの公式ページにも詳しい解説が載ってるので、ぜひ見てみてください。
http://docs.aws.amazon.com/ja_jp/AmazonS3/latest/dev/UploadObjSingleOpPHP.html

以上!

【Javascript】iPhone Safariで時刻のソートが効かない!

Javascriptを使って、オブジェクトが入ってる配列を「時刻文字列」順にソートしようとしたんです。

そうしたら、PCの「Chrome」ではちゃんと動作したコードが「iPhone Safari」では動作しませんでした・・。

コードは以下のようなもの(time_listの配下にある「timestamp」の時刻でソートします)

  time_list.sort(function(a,b){
    var t1 = new Date(a.timestamp);
    var t2 = new Date(b.timestamp);
    if( t1.getTime() > t2.getTime() ) return 1;
    if( t1.getTime() < t2.getTime() ) return -1;
    return 0;
  });


エラーとなる原因は、iPhone Safariで使える時刻フォーマットに厳しい制限があるためでした。例えば私が使っていた「2016-11-20 12:00:00」みたいな「-」が入った時刻表記はNGみたいです。

(※各種ブラウザで使える時刻フォーマットは以下)
Dateオブジェクト (日付と時刻) | JavaScript プログラミング解説

しょうがないので、私はその場しのぎで「-」を「/」に変換して「2016/11/20 12:00:00」という時刻表記にして対処しました。この表記ならiPhone SafariではOKみたいです。

  time_list.sort(function(a,b){
    var t1_str = a.timestamp;
    var t2_str = b.timestamp;
    t1_str = t1_str.replace(/-/g, "/");
    t2_str = t2_str.replace(/-/g, "/");
    var t1 = new Date(t1_str);
    var t2 = new Date(t2_str);
    if( t1.getTime() > t2.getTime() ) return 1;
    if( t1.getTime() < t2.getTime() ) return -1;
    return 0;
  });

この方法でもアンドロイドで大丈夫なのかとか、他のPCブラウザで大丈夫なのかとか、いろいろ心配ですね・・。

もっとちゃんと確認した方がよいとは思いますが、当面はこれでよしとしておきます・・。
以上です!

【CakePHP3】Layoutファイルの中でConfigureのパラメータを参照する!

CakePHP3の話なんですが、「/config/bootstrap.php」内で、全ての箇所から呼び出し可能な「グローバル変数」を定義することができます。

定義の仕方は以下のようにします(hogegeという変数を定義しています)

//定数を定義
Configure::write('hogege', 'hogegeだお!');

呼び出すときは以下のようにします。

//hogegeの値を読み込む!
$test = Configure::read('hogege');

これをレイアウトファイルとかテンプレートファイル内で読み込むときは、先頭で「use Cake\Core\Configure;」の宣言が必要なのでご注意ください。

以上!

Wi-Fiの調子が悪かったけどチャンネル幅の設定をいじったら直った!

ずっとWi-Fiの通信が不安定だったんですけど、ルーターの設定をいじったらだいぶ良くなりました。

ルーターは「PR-500KI」というNTTの装置で、無線の子機はエレコムの「WDC-300SU2S」という安いUSBのアダプタです。

ルーターの「チャネル帯域」という設定を「40MHz」から「20MHz」に直したら、かなり具合が良くなりました。

チャネル帯域が40MHzだと、チャネルボンディングという技術を使っていて高速な通信ができるんですけど、お隣さんの無線と干渉しやすくなってしまう欠点があるんだそうです。

私の無線の使用チャネルは「6番」で、お隣りさんの無線の使用チャネルは「1番」だったんですけど、おそらくこれだと干渉が起きてしまっていたんだと思いますね。

ルーターの「自動設定モード」でおすすめされたチャネル番号を使っていたんですが、このモードはあまり賢くチャネルを選んではくれないみたいです。

やっぱり最後は人間の手で設定しないといけません。

人間の最後の敵はやはり同じ人間である、ということなんでしょうかね・・(意味不明)

グーグル広告にボットが潜んでいてアクセス数が回りまくってしまう!

先日変な問題が起きて、頭を悩まされてしまいました・・。

私のサイトにアクセスすると、アクセスカウンターが二回加算されてしまうという問題です。

この問題、どうもグーグルアドセンスを張っているときに発生する様子です。

ページ中のグーグル広告が読み込まれたタイミングで、サイトになんらかのボットからアクセスが来て、カウンターを回していってしまう、という現象が起きているみたいでした。

ボットのユーザーエージェントを調べてみると、以下のような奴がアクセスにきてました(いかにもあやしい名前ですね・・)

Mozilla/5.0 (compatible; proximic; +http://www.proximic.com/info/spider.php)

この不具合の対応どうすればいいでしょうかね、とりあえずこのユーザーエージェントがアクセスしてきたときは、カウンタを回さないようにすればいいでしょうか。でも、他の種類のボットがアクセスしてきたときはどうすればいいんでしょうか・・?

アクセスカウンターって意外と作るの難しいんですね、こういう変なアクセスはちゃんと遮断しないといけない。

ちょっぴり実装を舐めていました・・。

以上です!