k01ken’s b10g

He110 W0r1d!

Windows10にBlenderを使う

開発環境は、Windows 10 Pro(64bit)。

1.公式サイトへアクセスし、画面をクリック
blender.org - Home of the Blender project - Free and Open 3D Creation Software
f:id:k01ken:20190206220441p:plain

2.Download Blender 2.8 Beta(現時点)と書かれたボタンをクリック
f:id:k01ken:20190206220456p:plain

3. 2.80 Beta Windows 64bit(現時点)をクリックし、zipファイルをダウンロード
f:id:k01ken:20190206220514p:plain

4.blender-2.80-8996e26116f0-win64.zipを解凍するだけ

5.解凍したディレクトリ内のblender.exeを実行

6.実行すると、Windows Defenderがストップする可能性があるので、詳細をクリックして、実行ボタンをクリックすると、Blenderが実行される。

7.中央のウィンドウのNextボタンをクリック
f:id:k01ken:20190206221802p:plain

8.New FileのGeneralをクリック
f:id:k01ken:20190206221817p:plain

おすすめリンク
Blender入門 - CGrad Project

PHPでarray_searchを使用する際の注意点

開発環境は、PHP 7.2.12。

条件文の中で使用する際に注意すべき部分

array_search関数は、配列の中に指定の値があれば、その値のキーを、指定の値がなければ、falseを返す関数なのですが、例えば、以下のコードのように、返り値としてインデックス番号の0が返る場合は、指定の要素があるのに、false扱いになってしまいます。

<?php
$arr = ["test", "test2","test3"];

# false
if( array_search("test", $arr) ){
  echo "true";
}else{
  echo "false";
}
?>

そこで、以下のようにコードを書き換えておきます。仮に、!== falseの部分を、!= falseとしてしまうと、同様に、falseと出力されてしまいます。
厳密な型の比較を確実に行い、意図しない動作を防ぐことが求められます。

<?php
$arr = ["test", "test2","test3"];

# true
if( array_search("test", $arr) !== false){
  echo "true";
}else{
  echo "false";
}
?>

条件文を書く際には、注意したい。

条件文内で変数を入れる際の注意点

array_searchを2回呼び出すのが処理的にどうなの?と思ったので、条件文内の変数に入れておこうと考えたが、想定した通りの動きにはならなかった。

<?php

$arr = [1,2,3,4,5];

if($idx = array_search(3,$arr) !== false){
  echo $idx; # 1が入る。
  echo array_search(3,$arr); # 2が入る
}
?>

文字列の値を用いてarray_searchを用いる際の注意点

文字列を値に指定する場合は、第三引数をtrueに指定しないと、きちんと動作しない。

<?php

$arr = [0,1,2,3,4,"str",5,"key" => "value",6,7,8];

print_r( array_search("str",$arr) ); # 5ではなくて0が返ってくる
print_r( array_search("str", $arr, true) ); # 5が返ってくる
print_r( array_search("value",$arr) ); # keyではなく0が返ってくる 
print_r( array_search("value",$arr,true) ); # keyが返ってくる 

?>


参考サイト
PHP: array_search - Manual

ImagicKを使って色々と画像を加工してみる

開発環境は、PHP 7.2.12 + ImageMagicK ImageMagick 7.0.7-11 Q16 x86 2017-11-23 + XAMPP Control Panel v3.2.2。

新しく画像を作成する

新しく画像を作成し、png画像のフォーマットとして、表示させます。

<?php
$image = new Imagick();
$image->newImage(100, 100, new ImagickPixel('red'));
$image->setImageFormat('png');

header('Content-type: image/png');
echo $image;
?>

実行結果
f:id:k01ken:20190125231848p:plain

画像を保存する

<?php
$image = new Imagick();
$image->newImage(100, 100, new ImagickPixel('red'));
$image->setImageFormat('png');

$image->writeImage(realpath("test.png"));
?>

と書く。writeImageのファイル名は絶対パスで指定すること。

参考リンク
http://php.net/manual/ja/imagick.writeimage.php

画像のサイズを変更する

以下のコードは、読み込んだ画像を、幅203px、高さ293pxに変換して表示している。

<?php
$image = new Imagick(realpath('test.jpg'));
$image->thumbnailImage(203,293);

header("Content-type: image/jpeg");
echo $image;
?>

thumbnailImage関数の第1引数か、第2引数を0にすると、指定した幅 or 高さに応じて自動的に、0を指定した幅 or 高さを調節してくれる。もし、高さを知りたければ、Imagick::getImageHeight関数を用いると高さを取得できる。

<?php
$image = new Imagick(realpath('test.jpg');
$image->thumbnailImage(220,0); # 例えば、高さは318pxに自動的になる

header("Content-type: image/jpeg");
echo $image;
?>

参考リンク
http://php.net/manual/ja/imagick.thumbnailimage.php
http://php.net/manual/ja/imagick.getimageheight.php
http://php.net/manual/ja/imagick.getimagewidth.php

画像の品質を変更/取得する

スクリプトのある同一ディレクトリにtest.jpgがあったとして、画像の圧縮品質を取得します。品質が高いと画像のファイルサイズが大きくなり、逆に、低いとファイルサイズが小さくなります。
値は1~100のどれかになります。

<?php
$img = new \Imagick(realpath("test.jpg"));
echo "<b>getImageCompressionQuality: </b>".$img->getImageCompressionQuality();

?>

次に画像の圧縮品質を変更してみたいと思います。
設定できる値は、1~100までです。jpeg画像だと、画像の見た目が変わりますが、png画像だと、画像の見た目は、全然変わりません。

<?php
$img = new \Imagick(realpath("test.jpg"));
$img->setImageCompressionQuality(100);
header("Content-Type: image/jpeg");
echo $img;
?>

参考リンク
https://www.php.net/manual/ja/imagick.getimagecompressionquality.php
https://www.php.net/manual/ja/imagick.setimagecompressionquality.php

画像を一部切り取って抜き出す

今回は入力した画像から、画像の中心を基準にして、正方形に切り出すプログラムを書いてみたいと思います。

<?php
$im = new Imagick(realpath('test.jpg'));
$width = $im->getImageWidth();
$height = $im->getImageHeight();

$half_width = $width / 2;
$half_height = $height / 2;

if($width > $height){
  # 縦幅の方が短い横長の画像
  $upper_half_width = $half_width - $half_height;
  $im->cropImage($height,$height, $upper_half_width,0);
}else if($width < $height){
  # 横幅の方が短い縦長の画像
  $upper_half_height = $half_height - $half_width;
  $im->cropImage($width,$width,0,$upper_half_height);
}else{
  # 最初から正方形の場合の画像
  $im->cropImage($width,$height,0,0);
}

$im->setImageFormat('jpg');

header("Content-type: image/jpg");
echo $im;

参考リンク
http://php.net/manual/ja/imagick.cropimage.php

2枚の画像を比較して差分を抽出する

下記の2枚の画像を使用します。
f:id:k01ken:20190125214822p:plain
f:id:k01ken:20190125214839p:plain

下記のプログラムでは、画像のパスは絶対パスで指定しないとエラーになる。

<?php

$image1 = new imagick("C:/xampp/htdocs/image1.png");
$image2 = new imagick("C:/xampp/htdocs/image2.png");

$result = $image1->compareImages($image2, Imagick::METRIC_MEANSQUAREERROR);
$result[0]->setImageFormat("png");

header("Content-Type: image/png");
echo $result[0];

?>

実行結果
f:id:k01ken:20190125215121p:plain

このように差分のみが赤く表示されていることが分かります。
サイトの中でデザインのどこが変更されたのか知るのにちょうどよいでしょう。


参考リンク
http://php.net/manual/ja/imagick.compareimages.php
Imagick::compareImages - ある画像を再構築された画像と比較する


画像のフォーマットを変換する

画像のフォーマットを変更するには、setImageFormat関数を用います。
例えば、以下のコードにて、読み込んだjpeg画像をpng画像に変換して表示します。

<?php

$image = new Imagick(realpath('test.jpg'));
$image->setImageFormat('png');

header("Content-Type: image/png");
echo $image;

?>

参考リンク
PHP Imagick で画像フォーマット変換 – rilakkuma3xjapan's blog

画像を半透明にする

自分の環境ではなぜか、setImageOpacity関数がなかったので代替方法を探して、あったので書いておきます。

<?php
$image = new Imagick();
$image->newImage(300,300,new ImagickPixel('black'));
$image->setImageFormat('png');

$image->transparentPaintImage(new ImagickPixel('black'), 0.8,10,false);

header("Content-Type: image/png");
echo $image;

?>

実行結果
f:id:k01ken:20190131232029p:plain

参考リンク
http://php.net/manual/ja/imagick.transparentpaintimage.php

画像を合成する

<?php
  $image = new Imagick();
  $image->newImage(600,600, new ImagickPixel('#cccccc'));
  $image->setImageFormat('png');

  $image2 = new Imagick();
  $image2->newImage(300,300, new ImagickPixel('#ffffff'));
  $image2->setImageFormat('png');

  $image->setImageVirtualPixelMethod(Imagick::VIRTUALPIXELMETHOD_TRANSPARENT);
  $image->setImageArtifact('compose:args', "1,0,-0.5,0.5");
  $image->compositeImage($image2, Imagick::COMPOSITE_MATHEMATICS, 0, 0); 

  header('Content-Type: image/png');
  echo $image;
?>

実行結果
f:id:k01ken:20190606220543p:plain

上に被せる画像が透過PNGだと、setImageVirtualPixelMethod,setImageArtifactを除いて、表示させると、シルエットとして表示されます。


参考リンク
https://www.php.net/manual/ja/imagick.compositeimage.php

Windows10にてプログラミング言語Goをインストールする

開発環境はWindows10 Pro(64bit)。

1.公式サイトへアクセスする
https://golang.org/

2.Download Goボタンをクリック
f:id:k01ken:20190125001401p:plain

3.Microsoft Windowsのgo1.11.5.windows-amd64.msiのリンクをクリックし、インストーラをダウンロード。
f:id:k01ken:20190125001410p:plain

4.ダウンロードしたインストーラを実行

5.Nextボタンをクリック
f:id:k01ken:20190125001427p:plain

6.Nextボタンをクリック
f:id:k01ken:20190125001437p:plain

7.Nextボタンをクリック
f:id:k01ken:20190125001444p:plain

8.Installボタンをクリック
f:id:k01ken:20190125001453p:plain

9.Finishボタンをクリック
f:id:k01ken:20190125001504p:plain

CakePHP3にてシェルとタスクを利用してコマンドラインからデータベースのデータを操作する

開発環境は、Windows 10 Pro(64bit) + PHP 7.2.12 + CakePHP 3.6.14 + XAMPP Control Panel v3.2.2。

基本的な操作

以下のプログラムをHelloShell.phpの名前でsrc/Shellディレクトリ内に保存する。

<?php

namespace App\Shell;

use Cake\Console\Shell;

class HelloShell extends Shell
{
    public function main()
    {
        $this->out(__('Hello world.'));
    }
}

?>

コマンドラインのカレントディレクトリをアプリのルートディレクトリにしてから、

bin\cake hello

と入力すると、Hello world.と表示されます。
main()関数の中に処理を書いておくと、

bin\cake hello main

のように書かなくても、省略して実行できます。なので、main()関数以外の名前で、関数を使いたければ、例えば、hoge()と書いて、その中の処理を書いて、実行する際は、

bin\cake hello hoge

と入力すればOKです。

データベースへアクセスして操作してみる

1.テストのために以下のテーブルを作成します。

create table samples(
  id int auto_increment primary key,
  data varchar(255) not null,
  created datetime,
  modified datetime
)charset=utf8mb4;

2.カレントディレクトリをアプリのルートディレクトリにして以下のコマンドを入力して、作成したテーブルに関係するファイルを自動的に作成しておきます。

bin\cake bake all samples

3.上記のHelloShell.phpを以下のソースコードに置き換えてください

<?php
namespace App\Shell;

use Cake\Console\Shell;

class HelloShell extends Shell
{
    public $tasks = ['Template'];

    public function main($taskname = '')
    {
				if($taskname === 'add'){
					$this->Template->main();
				}else if($taskname === 'delete'){
					$this->Template->delete();
				}else{
					$this->out(__('No Task.'));
				}
    }
}
?>

関数に引数を書くとコマンドラインから入力された値を受け取ることができます。


4. .src/Shellディレクトリ内にTaskディレクトリを作成します。

5.次に、Taskディレクトリ内に、TemplateTask.phpの名前で以下のコードを保存します。

<?php
namespace App\Shell\Task;

use Cake\Console\Shell;
use Cake\I18n\Time;
use Cake\ORM\TableRegistry;

class TemplateTask extends Shell
{

		public function initialize(){
			  date_default_timezone_set('Asia/Tokyo');
		}

    public function main()
    {
				$samples = TableRegistry::getTableLocator()->get('Samples');
				$query = $samples->query();
				$query->insert(['data','created','modified'])
					->values([
						'data' => '投稿しました',
						'created' => Time::now(),
						'modified' => Time::now()
					])
					->execute();
        $this->out(__('Insert Data.'));
    }

		public function delete(){
				$samples = TableRegistry::getTableLocator()->get('Samples');
				$query = $samples->query();
				$query->delete()
				->where(function($exp, $q){
					return $exp->lte("created", new Time('1 hours ago') );
				})
				->execute();

		$this->out(__('Delete Data.'));
		}
}
?>

6.カレントディレクトリをアプリのルートディレクトリにして、
以下のコマンドを実行すると、データが追加されます。

bin\cake hello add

以下のコマンドを実行すると、データを入力して1時間経過したデータを削除します。

bin\cake hello delete

それ以外に、単に、

bin\cake hello

と入力したり、hello以降に適当な値を入力しても、

bin\cake hello hoge

No Task.というメッセージが表示されるだけになります。


・Authコンポーネントを利用して認証機能を実装して、ログインしないと、データを追加や更新や削除できないようにしても、シェル経由で、データを追加や更新や削除することができるみたいです。


■本番環境ではどうなのか?(ロリポップの場合)
レンタルサーバーのロリポップのスタンダードプランでやってみたところ、CakePHPは普通に動作できるが、cronを使用したり、SSLでアクセスして、手動で実行させようと、bin/cake.phpを動作させると、PHPのバージョンはPHP 5.5.35 (cli) で、CakePHPを使用するには、5.6.0以上にしろと表示され、実行できない。

そこで、推奨できないが、緊急策として、CakePHPを介さずに、PHPでデータベースに直接アクセスして、データを追加するプログラムを作ってみた。このプログラムを実行するたびに、samplesテーブルにデータが追加される。

<?php

date_default_timezone_set('Asia/Tokyo');
$now = date("Y/m/d H:i:s");
$url = "";
$user = "";
$password = "";
$database = "";
$connect = mysql_connect($url,$user,$password) or die("can't connect");
$db = mysql_select_db($database, $connect) or die("can't Select database");
$sql = "INSERT INTO samples (data,created,modified) VALUES ('test', '$now', '$now');";
$result = mysql_query($sql,$connect);
echo $result;

?>

ただ、

上記のプログラムを検証してみると、SSLでログインして、php 絶対パスor 相対パスでのphpのプログラム名では、うまく動作するが、cronで、そのプログラムを指定すると、うまく動作しなかった。原因は分からないが、検証したところ、どうも、mysql_connect部分がおかしいみたい。

そこで、以下のようなPDOを利用したプログラムに切り替えると、cronでもきちんと動作した。

<?php

date_default_timezone_set('Asia/Tokyo');
$now = date("Y/m/d H:i:s");

$url = "";
$user = "";
$password = "";
$database = "";

$dbh = new PDO("mysql:dbname=$database;host=$url",$username,$password);

$count = $dbh->exec("INSERT INTO samples (data,created,modified) VALUES ('test', '$now', '$now')");
echo $count;

?>

参考リンク
シェル - 3.7
日付と時刻 - 3.7
データベースアクセス & ORM - 3.7
クエリービルダー - 3.7
PHPでデータベースに接続するときのまとめ - Qiita
データの追加(INSERT文) - データの追加と削除 - MySQLの使い方
PHPでmysql_connect関数を使いMySQLへ接続するサンプルです。 · GitHub
PHP: PDO - Manual
データの削除(DELETE文) - データの追加と削除 - MySQLの使い方

ロリポップのcronでプログラムを定期実行してみる

プランによってcronの使用制限があります。自分の場合はスタンダードなので、
10個までcronが登録できて、1分毎に作動できます。
cron設定 / サーバー・プログラム / マニュアル - レンタルサーバーならロリポップ!

今回はテストとしてサンプルプログラムを1分ごとに起動したいと思います。

1.ユーザー管理ページへログインする
https://user.lolipop.jp/

2.左サイドバーのサーバーの管理・設定 - cron設定をクリック

3.ルート部分のwebディレクトリに、test_cronディレクトリを作成して、その中に、以下のコードをcron.phpで保存します。

<?php
  date_default_timezone_set('Asia/Tokyo');

  $handle = fopen("test.txt", "a+");
  fwrite($handle, date("Y-m-d H:i:s")."\r\n");
  fclose($handle);
?>

4.
cronの設定名はtest_cron
日付 ( 月 )は、毎月
日付 ( 日 )は毎日
曜日は毎日
時間 ( 時 )は毎時
時間 ( 分 )は1分毎
実行ファイルパスはtest_cron/cron.php
と記入し、設定ボタンをクリックすると作成する

5.これによって、1分ごとに現在時刻がtest.txtに追加されていきます。


※今回はサンプルプログラムなので、作成したcronを削除することを忘れないでください。

CakePHP3でPHPUnitを使ってテストを行う

開発環境は、Windows 10 Pro(64bit) + PHP 7.2.12 + CakePHP 3.6.14 + XAMPP Control Panel v3.2.2。

前提として、
CakePHPの組み込みサーバー
・XAMPPのApache
・XAMPPのMySQL
が起動しています。

今回は、初めてなので公式ドキュメントに基づいて書いておきます。



1.CakePHPの公式ドキュメントに基づき、コマンドを入力して、composerでphpunitをインストールする
https://book.cakephp.org/3.0/ja/development/testing.html

composer require --dev phpunit/phpunit:"^5.7|^6.0"
vendor\bin\phpunit --version

と入力して、バージョン情報が表示されたら、きちんとインストールされています。


2.次に、CakePHPの公式ドキュメントに基づき、ヘルパーとヘルパーのテストを作成します。

https://book.cakephp.org/3.0/ja/development/testing.html#id6
最初のテストケースの欄の、ProgressHelperクラスについて書かれたコードをコピペし、<?php ~ ?>で囲って、src/View/Helperディレクトリに、ProgressHelper.phpという名前で保存します。
次に、ProgressHelperTestクラスについて書かれたコードをコピペし、<?php ~ ?>で囲って、setUp()関数とtestBar()関数の中身もコピペして入力し、tests/TestCase/View/HelperディレクトリにProgressHelperTest.phpという名前で保存します。
※CakePHP4からは、setUp()関数を、public function setUp(): voidという風に書くこと。そうしないと、以下のようなエラーメッセージが表示される。

PHP Fatal error:  Declaration of App\Test\TestCase\View\Helper\ProgressHelperTest::setUp() must be compatible with Cake\TestSuite\TestCase::setUp(): void in C:\test_cakephp\tests\TestCase\View\Helper\ProgressHelperTest.php on line 9

※サンプルコードでは、assertContains()を用いているが、代わりに、assertStringContainsString()を使う。そうしないと、以下のようなメッセージが表示して、テストが成功しない。

1) App\Test\TestCase\View\Helper\ProgressHelperTest::testBar
Using assertContains() with string haystacks is deprecated and will not be supported in PHPUnit 9. Refactor your test to use assertStringContainsString() or assertStringContainsStringIgnoringCase() instead.


3.次に、テストを実行してみます。サーバーとデータベースが実行していることを確認し、以下のコマンドを入力して実行します。

vendor\bin\phpunit tests/TestCase/View/Helper/ProgressHelperTest.php

これできちんとテストが実行されたと思います。

特定のテストメソッドだけを実行したければ、

vendor\bin\phpunit --filter testIndex tests/TestCase/Controller/PostsControllerTest.php

のように実行します。



4.次に下記のリンクのコードカバレッジの生成の欄に基づき、
https://book.cakephp.org/3.0/ja/development/testing.html#id9
下記のコードを入力した時に、テスト結果が視覚的に見やすく表示されるようにしたいと思います。

vendor\bin\phpunit --coverage-html webroot/coverage tests/TestCase/View/Helper/ProgressHelperTest.php

そのためには、まず、現在の環境にXdebugをインストールする必要があります。
もし、インストールしていなければ、テスト結果に、

Error:         No code coverage driver is available

のメッセージが表示されることになります。
そこで、localhostでXAMPPのトップページにアクセスして、上部のPHPInfoの欄へアクセスします。
f:id:k01ken:20190115183535p:plain

下記のページへアクセスしておきます。
Xdebug: Support — Tailored Installation Instructions

PHPInfoのページにて、Ctrlを押しながらAを押して、ページ全体を反転させて、Ctrlを押しながらCを押して、コピーします。

上のページの四角い枠にCtrlを押しながらVを押して、ペーストし、Analyse my phpinfo() outputボタンをクリックします。

そうすると、最適なxdebugのdllファイルが選択されるので、
You're already running the latest Xdebug version
に書かれている手順通りに行うと、Xdebugが実行できます。
先ほどのPHPInfoのページにアクセスして、xdebugで検索して、以下のような欄があれば成功です。
f:id:k01ken:20190115184934p:plain


最後に、もう一度、上記のコードを入力した後に、

vendor\bin\phpunit --coverage-html webroot/coverage tests/TestCase/View/Helper/ProgressHelperTest.php

localhost:8765/coverage/index.htmlへアクセスすると、表示されていると思います。
f:id:k01ken:20190115185643p:plain

参考リンク
Cake PHP3のphpunitでコードカバレッジ見たいのに見られない - キーボードはパンタグラフが好き
【CakePHP3】PHPUnitでテストの自動化 | INSIGHT
xdebugをwindowsのphpに設定する方法で悩んだ件 - Qiita
CakePHP3でControllerのユニットテストを書く例 - Qiita