PHP デバッグ方法(XAMPP/Eclipse/Xdebug)

Xdebugモジュール

ダウンロード

phpinfo()を出力


https://xdebug.org/wizard.php
のテキストエリアにphp_info()の出力結果を貼り付け


「Analyse my phpinfo() output」ボタン押下


分析されたモジュールをダウンロード
例:php_xdebug-2.6.1-7.2-vc15.dll

保存

C:\xampp\php\ext\
に保存

XAMPP

読み込み

C:\xampp\php\php.ini
に以下を追加

[XDebug]
;; Only Zend OR (!) XDebug
zend_extension_ts="C:\xampp\php\ext\php_xdebug.dll"
xdebug.remote_enable=true
xdebug.remote_host=127.0.0.1
xdebug.remote_port=9000
xdebug.remote_handler=dbgp
xdebug.profiler_enable=1
xdebug.profiler_output_dir="C:\xampp\tmp"

Eclipse

デバッグの構成

サーバータブ

「PHP Webアプリケーション」をダブルクリック
名前を保存可能

ファイル:デバッグ対象のファイルを選択
URL:CakePHPの場合、URLが実ファイルと変更されるのでブラウザに表示されるURLを入力

サーバー:構成
ベースURL:ポート番号等変更がある場合

デバッガータブ


デバッカー:XDebugを選択

PHP Smarty

設定

ライブラリ

https://www.smarty.net/

配置

ライブラリ
smarty-X.X.X
 └demo
 └libs
  └Smarty.class.php
  └他
コンパイルファイル配置場所
compile
テンプレートファイル配置場所
template
 └test.tpl

テンプレート

※test.tpl
<!DOCTYPE html>
<html>
<head>
 <meta charset="UTF-8">
 <title>~</title>
</head>
<body>
 埋め込み用変数
 <p>{$val1}</p>
 <p>{$val2}</p>
</body>
</html>

テンプレート利用

※~.php
<?php
require_once '~/smarty-X.X.X/libs/Smarty.class.php';

$smarty = new Smarty();
テンプレートファイル配置場所指定
$smarty->template_dir = '~/template';
コンパイルファイル配置場所指定
$smarty->compile_dir = '~/compile';

テンプレートファイルの変数へ値を埋め込み
$smarty->assign('val1', 999);
$smarty->assign('val2', 'aaa');
描画
$smarty->display('test.tpl');

Hexo使用方法

Hexoインストール

# npm install -g hexo

雛形作成

# cd (ディレクトリ)
# hexo init (サイト名)

モジュールインストール

# cd (サイト名)
# npm install

ローカルWEBサーバ起動

# hexo server

ローカル動作確認
http://localhost:4000/

GitHub Pagesへデプロイ

デプロイツールインストール

npm install hexo-deployer-git –save

設定ファイル編集

_config.yml

deploy:
 type:git
 repo https://office-yone@github.com/office-yone/office-yone.github.io.git
 branch: master

リモートリポジトリにデプロイ

hexo deploy -g

リモートリポジトリ動作確認
github pagesをブラウザで表示
https://office-yone.github.io/index.html

CakePHP ページネーション機能(Paginator)

基本

コントローラ

設定

public $paginate = [
 'limit' => 5,
 並び順設定はデータ取得時に実施する方が自由度が高いのでここでは行わない
 'order' => [
   'id' => 'DESC'
 ],
 アソシエーションデータ取得時に実施する方が自由度が高いのでここでは行わない
 'contain' => ['People']
];

Paginatorコンポーネント読み込み

public function initialize(){
 parent::initialize();
 ↓ は不要(デフォルトで使用できる)
 $this->loadComponent('Pagenator');
}

ページネーションを利用したデータ取得

public function list(){
 $lists = $this->paginate(
  $this->Products
   ->find()
   ->contain(['~'])
   ->where(['~ !=' => '0'])
   ->order(['~' => 'DESC', '~' => 'DESC'])
   );
  $this->set(compact('lists'));
}

ビュー

ページ移動

※~\src\Template\(コントローラ名)\(ビュー名).ctp
<div class="paginator">
 <ul class="pagination">
  <?= $this->Paginator->first('<< ' . '最初') ?>
  <?= $this->Paginator->prev('< ' . '前へ') ?>
  <?= $this->Paginator->numbers() ?>
  <?= $this->Paginator->next('次へ' . ' >') ?>
  <?= $this->Paginator->last('最後' . ' >>') ?>
 </ul>
</div>

ページ番号

【通常】
<?= $this->Paginator->numbers() ?>

【オプション】
<?=
  $this->Paginator->numbers([
    現ページより前のページがあれば'<<'を表示
    'before' => $this->Paginator->hasPrev() ?
     $this->Paginator->first('<<') : '',
    現ページより後のページがあれば'>>'を表示
    'after' => $this->Paginator->hasNext() ?
     $this->Paginator->last('>>')
    'modules' => 4
    'separator' => '|'
  ]);
?>

設定項目 機能
before 最初のリンクの前に表示する内容
after 最後のリンクの前に表示する内容
modules カレントページ番号を除いた表示リンク数
2の場合→1,2(カレント),3
separator リンク間区切り文字

カウンター

<?=
 $this->Paginator->counter([
  'format' => 'ページ {{page}} / {{pages}}, レコード {{current}} / {{count}} '])
?>

メソッド

メソッド 機能
next
prev
first 最初
last 最後
counterRange カウンター(format=rangeの場合)
counterPages カウンター(format=pagesの場合)
numbers ページ番号
current 現在ページ番号
sort ソートヘッダー(並び順未指定)
sortAsc ソートヘッダー(昇順)
sortDesc ソートヘッダー(降順)

組込変数

変数名 機能
{text} ページ番号
{url} 遷移先URL
{page} 現ページ番号
{pages} 総ページ数
{current} 現ページでのレコード数
{count} 総レコード数

独自リンク

テンプレート

※~\config\my-paginator-temp.php
<?php

$number  = '<span style="';
$number .= 'border: solid 1px black; ';
$number .= 'padding: 10px; ';
$number .= 'margin: 1px; ">';
$number .= '<a href="{{url}}">{{text}}</a>';
$number .= '</span>';

$current  = '<span style="';
$current .= 'background-color: black; ';
$current .= 'color: white; ';
$current .= 'border: solid 1px black; ';
$current .= 'padding: 10px; ';
$current .= 'margin: 1px; ">';
$current .= '{{text}}';
$current .= '</span>';

return [
 'number' => $number,
 'current' => $current
];

テンプレート読み込み

※~\src\View\AppView.php
class AppView extends View
{
 public function initialize()
 {
  $this->loadHelper(
   'Paginator', [
    'templates' => 'my-paginator-temp'
   ]);
 }
}

CakePHP CSV出力機能(friendsofcake/cakephp-csvview)

インストール

Composerからライブラリインストール
# composer require friendsofcake/cakephp-csvview:~3.0

設定

※~/config/bootstrap.php
Plugin::load('CsvView');

コントローラ

直接出力

public function receiptDownload(){

 出力対象
 $receipts = $this->Receipt
  ->find()
  ->all();

 $_serialize = ['receipts'];

 ヘッダー(※省略可)
 $_header = ['Column 1', 'Column 2', 'Column 3'];

 フッター(※省略可)
 $_footer = ['件数:' . $receipts->count()];

 ファイル名(※省略可)
 $this->response->download('売上一覧.csv');

 CsvViewを利用
 $this->viewBuilder()->className('CsvView.Csv');

 設定値をプラグインへ引き渡し
 $this->set(compact('receipts', '_serialize', '_header', '_footer'));
}

テンプレート使用

public function receiptDownload(){

 出力対象
 $receipts = $this->Receipt
  ->find()
  ->all();

 $_serialize = null;

 ファイル名(※省略可)
 $this->response->download('売上一覧.csv');

 CsvViewを利用
 $this->viewBuilder()->className('CsvView.Csv');

 設定値をプラグインへ引き渡し
 $this->set(compact('receipts', '_serialize'));
}

\src\Template\(コントローラ名)\csv\receipt_download.ctp
<?php foreach ($receipts as $receipt): ?>
  列名、デミリタ(,)を指定
  <?php echo $receipt->id ?><?php echo ',' ?>
  <?php echo $receipt->col1 ?><?php echo ',' ?>
  <?php echo $receipt->col2 ?><?php echo ',' ?>
  JOINした場合の複層モデルを指定
  <?php echo $receipt->Model1['col'] ?><?php echo ',' ?>
  最終列には改行を指定
  <?php echo $receipt->Model2['col'] ?><?php echo 'PHP_EOL' ?>
<?php endforeach; ?>

CakePHP 検索機能(friendsofcake/search)

インストール

composer require friendsofcake/search

設定

cd bin
cake plugin load Search

※~/config/bootstrap.php
Plugin::load('Search');

完全一致検索

ビュー

<form method="post" accept-charset="utf-8" action="~">
<div><?= $this->Form->text('name') ?></div>
<input type='submit' value='検索' />
<?= $this->Form->end() ?>

モデル

※~Table
public function initialize(array $config)
{
  parent::initialize($config);

  $this->addBehavior('Search.Search');
  $this->searchManager()
    ->value('name');
}

コントローラ

※~Controller
public function initialize()
{
  parent::initialize();

  $this->loadComponent('Search.Prg', [
    'actions' => ['(アクション名)']
  ]);
}

public function (アクション名)(){
  $query = $this->(モデル名)
    ->find('search', ['search'=>$this->request->query]);
  $this->set('(変数名)', $this->paginate($query));
}

あいまい検索

ビュー

<form method="post" accept-charset="utf-8" action="~">
<div><?= $this->Form->text('name') ?></div>
<input type='submit' value='検索' />
<?= $this->Form->end() ?>

モデル

※~Table
public function initialize(array $config)
{
  parent::initialize($config);

  $this->addBehavior('Search.Search');
  $this->searchManager()
    ->like('name',[
      'before' => true,
      'after' => true
    ]);
}

複数カラム検索

ビュー

<form method="post" accept-charset="utf-8" action="~">
<div><?= $this->Form->text('name1') ?></div>
<div><?= $this->Form->text('name2') ?></div>
<div><?= $this->Form->text('name3') ?></div>
<input type='submit' value='検索' />
<?= $this->Form->end() ?>

モデル

※~Table
public function initialize(array $config)
{
  parent::initialize($config);

  $this->addBehavior('Search.Search');
  $this->searchManager()
    ->add('name1',
      'Search.Like', [
      'before' => true,
    'after' => true,
    'mode' => 'or',
    'comparison' => 'LIKE',
    'wildcardAny' => '*',
    'wildcardOne' => '?',
    'field' => ['name1', 'name2', 'name3']
 ])
}

日付範囲検索

ビュー

<form method="post" accept-charset="utf-8" action="~">
<?= $this->Form->control('start_created', [
 'type'=>'text',
 'label'=>'開始',
 'id'=>'date_start']); ?>
<?= $this->Form->control('end_created', [
 'type'=>'text',
 'label'=>'終了',
 'id'=>'date_end']); ?>

jQuery処理
<?= $this->Html->scriptStart(['block' => true]) ?>
 $( function() {
  $( "#date_start" ).datepicker({
   dateFormat: 'yy-mm-dd'
  });
  $( "#date_end" ).datepicker({
   dateFormat: 'yy-mm-dd'
  });
 } );
<?= $this->Html->scriptEnd() ?>

<input type='submit' value='検索' />
<?= $this->Form->end() ?>

モデル

※~Table
public function initialize(array $config)
{
  parent::initialize($config);

  $this->addBehavior('Search.Search');
  $this->searchManager()
    ->callback('start_created', [
   'callback' => function ($query, $args, $filter) {
    if(empty($args['end_created'])) {
     return;
    }
    return $query->where(function ($exp) use ($args) {
     時間の最小/最大を付与
     $args['start_created'] .= ' 00:00:00';
     $args['end_created'] .= ' 23:59:59';
     return $exp->between(
       'products.created',
       $args['start_created'],
       $args['end_created']
      );
     });
    }
   ])

->callback('end_created', [
   'callback' => function ($query, $args, $filter) {}
 ])
}

別モデル検索

モデル

※~Table
public function initialize(array $config)
{
  parent::initialize($config);
  $this->addBehavior('Search.Search');
  $this->searchManager()

    他の検索と組み合わせ可
    ->like('col',[
      'before' => true,
      'after' => true,
      'field' => $this->aliasField('others.col')
    ])
}

コントローラ

※~Controller
public function initialize()
{
  parent::initialize();
  $this->loadComponent('Search.Prg', [
    'actions' => ['(アクション名)']
  ]);

}

public function (アクション名)(){
  $query = $this->(モデル名)
    ->find('search', ['search'=>$this->request->query]);
    ->contain(['others'])
  $this->set('(変数名)', $this->paginate($query));
}

CakePHP ファイルアップロード機能(josegonzalez/Upload)

インストール

Composerからライブラリインストール
# composer require josegonzalez/cakephp-upload

設定

ライブラリロード設定

# bin/cake plugin load josegonzalez/Upload

↓ にロード設定が追加される
※/config/bootstrap.php
Plugin::load('Josegonzalez/Upload.Upload');

モデル

class ProductsTable extends Table
{
 public function initialize(array $config)
 {
  parent::initialize($config);

  $this->setTable('products');
  $this->setDisplayField('id');
  $this->setPrimaryKey('id');

  $this->addBehavior('Timestamp');

  // Upload Plugin
  $this->addBehavior('Josegonzalez/Upload.Upload', [
   最小機能(アップロードのみ)
   'image' => [],

   ファイル名自動作成
   'image' => [
    'nameCallback' => function ($data, $settings) {
     return uniqid().'-'.strtolower($data['name']);
    }
   ],

   レコード削除時にファイルを削除
   'image' => [
     'keepFilesOnDelete' => false
   ],
  ]);
 }
}

ビュー

<?= $this->Form->create($product, ['type' => 'file']) ?>
 <?= $this->Form->control('image', ["type"=>"file"]); ?>
<?= $this->Form->end() ?>

PHP Composer

Composerとは

PHP用パッケージ管理アプリケーション
プロジェクト、ディレクトリ単位でコマンドラインからライブラリ等をインストールでき、
インストールされたクラスはrequire/include無しで利用が可能

インストール

curl -sS https://getcomposer.org/installer | php

実行確認
./composer.phar

公式サイト
https://getcomposer.org/Composer-Setup.exe
からインストーラをダウンロードして実行

コマンド

一覧

コマンド 内容
composer バージョン確認
composer self-update composerの更新
composer install ライブラリインストール
composer update ライブラリ追加/削除
composer show -i ライブラリ情報表示
composer init composer.json作成
composer create-project プロジェクト作成

composer install

※composer.json
{
 "require": {
  "guzzlehttp/guzzle": "4.0.*@dev"
 }
}

結果
ComposerTest
└composer.json
└composer.lock
└vendor
 └autoload.php
 └composer
 └guzzlehttp
 └composer
  └autoload_classmap.php
  └autoload_files.php
  └autoload_namespaces.php
  └autoload_psr4.php
  └autoload_real.php
  └autoload_static.php
  └ClassLoader.php
  └installed.json
  └LICENSE
 └guzzlehttp
  └~

利用方法
<?php
require_once("vendor/autoload.php");

$client = new GuzzleHttp\Client();
$res = $client->get('http://rss.rssad.jp/rss/codezine/new/20/index.xml');
echo $res->getBody();

composer create-project

composer create-project --prefer-dist プロジェクト名

例:cakephp
composer create-project --prefer-dist cakephp/app cakephptest

PHP 重要用語

PEAR

PHP Extension and Application Repository
PHP標準のライブラリリポジトリ
PerlでいうCPAN
コマンドラインからネットワーク経由でライブラリをインストールできる
実行にはRoot権限が必要
依存関係を解消するComposerの様な機能は無い
ComposerからPEARライブラリをインストールする事もできる

Composer

PHP Composer」参照

CakePHP 認証機能(CakeDC/Users)

インストール

composer require cakedc/users

設定

Security.salt設定

CakePHP インストール・設定/Security.salt設定」参照

ライブラリ読み込み

※~/config/bootstrap.php
Plugin::load('CakeDC/Users', ['routes' => true, 'bootstrap' => true]);

テーブル作成

cd bin
cake migrations migrate -p CakeDC/Users

管理者ユーザ作成

cake users add_superuser
※パスワードをメモ

cake users add_superuser -u (ログインID) -p (パスワード)

リダイレクト設定

外部ファイル指定

※~/config/bootstrap.php
Configure::write('Users.config', ['users']);

外部ファイル

※~/config/users.php
<?php
use Cake\Core\Configure;
use Cake\Routing\Router;

$config = [
  'Auth' => [
    ~
    ログイン後の遷移先
    URLを指定したが未ログインの為、ログイン画面へ飛ばされ、
    その後ログインに成功した場合はこの遷移先には飛ばずに最初の指定URLへ遷移する

    'loginRedirect' => [
      'plugin' => null,
      'controller' => 'Tests',
      'action' => 'index',
    ],
    CakeDCのユーザー一覧画面へ遷移させる場合
    'loginRedirect' => [
      'plugin' => 'CakeDC/Users',
      'controller' => 'Users',
      'action' => 'index',
    ],
    'logoutRedirect' => [
      'plugin' => null,
      'controller' => 'Tests',
      'action' => 'display', 'home',
    ]
  ],
];

return $config;

アクセス権限設定

※~/config/permissions.php
<?php
return [
  'Users.SimpleRbac.permissions' => [
    [
      ユーザーはユーザ用のコントローラ、アクションにアクセス可能
      'role' => 'user',
      'controller' => 'Test',
      'action' => '*',
    ],
    [
      スーパーユーザーは全てのコントローラ、アクションにアクセス可能
      'role' => 'superuser',
      'controller' => '*',
      'action' => '*',
    ],
  ]
];

※~Contoroller.php
public function initialize()
{
  
  ログイン無しでアクセス可能なアクションの設定
  $this->Auth->allow([
   'index',
   'search',
   'searchResult',
  ]);
}

メール設定

設定ファイル

CakePHP インストール・設定/メール設定」参照

テンプレート

メールメッセージ
vendor\cakedc\users\src\Template\Email\html\~
vendor\cakedc\users\src\Template\Email\text\~
からコピーして配置する

src
└Template
 └Plugin
  └CakeDC
   └Users
    └Email
     └html
      └reset_password.ctp
      └social_account_validation.ctp
      └validation.ctp
     └text
      └reset_password.ctp
      └social_account_validation.ctp
      └validation.ctp

日本語化

日本語ファイル作成

※\vendor\cakedc\users\src\Locale\ja_JP\Users.po
msgid "Please enter your username and password"
msgstr "ユーザー名 / パスワードを入力して下さい"

日本語ファイルを読み込み

※config\bootstrap.php
ini_set('intl.default_locale', Configure::read('App.defaultLocale'));
↓ を追加
ini_set('intl.default_locale', 'ja_JP');

reCAPTCHA

reCAPTCHAライブラリインストール

composer require google/recaptcha "~1.1"

キー取得

reCAPTCHA認証」参照

users.php

※~\config\users.php
$config = [
  'Users' => [
    ~
    'reCaptcha' => [
      // reCaptcha key goes here
      'key' => null,
      // reCaptcha secret
      'secret' => null,
      // use reCaptcha in registration
      'registration' => false,
      // use reCaptcha in login, valid values are false, true
      'login' => false,

    ↓

    'reCaptcha' => [
      // reCaptcha key goes here
      'key' => 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
      // reCaptcha secret
      'secret' => 'XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX',
      // use reCaptcha in registration
      'registration' => true,
      // use reCaptcha in login, valid values are false, true
      'login' => true,

コントローラ

コンポーネントロード

※~Contoroller.php
public function initialize()
{
  parent::initialize();
  ~
  $this->loadComponent('CakeDC/Users.UsersAuth');
}

ビュー

ヘルパー読込

※~\src\View\AppView.php
public function initialize()
{
 $this->loadHelper('CakeDC/Users.User');
}

ログアウト
$this->User->logout();
ログアウト画面へのHTMLリンクが生成される

組込画面

ログイン画面
http://~/login

ログアウト画面
http://~/logout

ユーザー:プロフィール画面
http://~/profile

管理者:ユーザー一覧
http://~/users/users/

管理者:ユーザー登録
http://~/users/users/add

ユーザー:登録画面
http://~/users/users/register

ユーザー:パスワードリセット画面
http://~/users/users/request-reset-password