画面にHTMLを表示する、時刻を表示する

PHPでHTMLを表示する場合はprint または echo を使用します。

<?php

print('ここに記入')

?>

時刻を表示するときはdateを使用します。

<?php
print(date('Y m j s'));
?>

dateファンクションは画面に表示する機能はもっておらず、【戻り値】として内容を得られるだけです。文字列と連結するときは、
.(ドット)を使って戻り値と文字列を連結します。

<?php
print('現在は'.date('G i s').'です')
?>

cakephp パスワードリマインダー機能の実装

cakephpでパスワードリマインダー機能を追加しました。あまり探してなかったので、フローとメモを記しておきます。

準備:

・Controller

UsersController.php

・Model

User.php

EmailSend.php

PasswordRemind.php

・View

forgot_password.ctp

reset_password.ctp

=========================================

流れ

①【forgot_password.ctp】 

*Controllerに渡すデータ値 

ユーザーネーム(メールアドレス)

これらをFormヘルパー:createの’action’ => ‘forgot_password’,で渡しています

================================================

②【UsersController.php】

*あるユーザーネームだけ取得します

function forgot_password(){

// フォームからポストされたデータがあるかどうか
if ($this->request->is(‘post’)) {
// 登録されているメールアドレスが存在するかどうか
$username = !empty($this->request->data[‘User’][‘username’])?$this->request->data[‘User’][‘username’]:”;  
$user_id = $this->User->userNameExists($username);  ・・・・・①

if(!empty($user_id)){ ・・・・②
// 存在すればURLを作成し、メール送信し、リセットパスワードを送信
//アクチベーション用のURLを作成
$url =
DS . strtolower($this->name) . // コントローラ
DS . ‘reset_password’ . // アクション
DS . $this->User->getPasswordRemindHash($user_id);
$url = Router::url( $url, true);
$this->EmailSend->sendPasswordRemindMail($username, $url, ‘forgot_password’);

$this->Session->setFlash(__(‘入力されたメールアドレス宛にパスワードリセットURLが記載されたメールを送信しました。メールを確認し記載されたURLにアクセスしてパスワードを新しいパスワードに更新してください。’));
return $this->redirect(array(‘controller’ => ‘users’,’action’ => ‘forgot_password’ ));
}else{
// 存在しなければ
$this->Session->setFlash(__(‘このメールアドレスは登録されていません。’));
}
}

=========================================================

①はModelのUser.phpにて、ユーザーIDでユーザー名(メールアドレス)が存在するかどうかを取得しています。

public function userNameExists($username) {
$result = $this->find(‘first’, array(
‘fields’ =>array(
$this->alias.’.id’,
),
‘conditions’ => array(
$this->alias.’.username’ => $username,
$this->alias.’.retired’ => false, ・・・・これは削除されていないよって意味だよ。削除されているユーザーを取得することはないのでここで指定しているんだよ。
),
‘recursive’ => -1, //Userのみ取得する
));
// 存在すればIDを返し、存在しなければfalseを返す
return !empty($result[‘User’][‘id’])?$result[‘User’][‘id’]:false;
}

*find関数 

*三項演算子 (条件式)?trueの時:falseの時;

===========================================================

【ここ重要!】

②はModel/User.phpのgetPasswordRemindHashアクションで

始めにユーザーネーム(メールアドレス)を取得し、次にハッシュ値を生成し、

そのユーザーネームに対するURLにハッシュをくっつけてます。

$this->log(“———-function getPasswordRemindHash–“.__FILE__.__LINE__.”\n”);
// ユーザIDの有無確認
if ($this->exists($user_id)) {
// 更新日時を取得しハッシュ化
$result = $this->find(‘first’, array(
‘conditions’ => array(
‘User.id’ => $user_id,
‘User.retired’ => false,
),
‘fields’ => array(
‘User.username’,
),
‘contain’ => array(),
‘recursive’ => -1, //Userのみ取得する
));
//modifiedによりハッシュを作成する。
$hash = $this->PasswordRemind->makeHash( $result[‘User’][‘username’]);
$this->PasswordRemind->saveHash($user_id, $hash);
return $hash;
}else{
//ユーザーが存在しなければfalse
return false;
}

====================================================

Model/PasswordRemind.php にて

public function makeHash($email = ”) {
//現在時刻とemailによりハッシュを作成する。
return Security::hash( $email . date(‘Y-m-d H:i:s’), ‘sha1’, true);
}

public function saveHash($user_id, $hash) {
$this->create();
$savedata = array(
‘user_id’ => $user_id,
‘hash’ => $hash,
‘created’ => date(‘Y-m-d H:i:s’), // 一応明示的に現在時刻をいれてあげる
);
return $this->save($savedata);
}

========================================================-

さあ、ここでEmailを送るのだが、いくつか注意点があります。(てか、いくつかエラーがでた)

ここではModel/EmailSend.php でメール送信を行っていますが、

まず、ソースは

function sendPasswordRemindMail($Email, $url, $template = null){

// メール送信

$email = new CakeEmail(‘password_remind’);
try {
$email->config(‘password_remind’);
// メーラー情報の削除 cake phpで作成されたことがバレバレになってしまうため。
$email->addHeaders(array(‘X-Mailer’ => false));
$email->emailPattern(‘/^[-+.\\w]+@[-a-z0-9]+(\\.[-a-z0-9]+)*\\.[a-z]{2,6}$/i’);
$email->to(array($Email));
$email->viewVars(compact(‘Email’));
$email->viewVars(compact(‘url’));
$email->template(‘refresh_password’, ‘default’);
$email->subject(Configure::read(‘MAIL_SUBJECT_HEADER’).Configure::read(‘MAIL_SUBJECT.password_remind’));

$result = $email->send();
$this->log(‘登録メール送信’.__FILE__.__LINE__);
} catch(Exception $e) {
try {
// “”で囲む処理を入れる
$arr = explode(‘@’,$Email);
$arr[0] = ‘”‘ .$arr[0] .'”‘ ;
$mail = $arr[0].’@’.$arr[1];

debug($e->getMessage());
$email->config(‘password_remind’);
// メーラー情報の削除 cake phpで作成されたことがバレバレになってしまうため。
$email->addHeaders(array(‘X-Mailer’ => false));
// “を許可する
$email->emailPattern(‘/^[-“+.\\w]+@[-a-z0-9]+(\\.[-a-z0-9]+)*\\.[a-z]{2,6}$/i’);
# $email->to(array($request_data[‘User’][‘username’]));
$email->to(array($mail));
$email->viewVars(compact(‘Email’));
$email->viewVars(compact(‘url’));

$email->template(‘refresh_password’, ‘default’);
$email->subject(Configure::read(‘MAIL_SUBJECT_HEADER’).Configure::read(‘MAIL_SUBJECT.password_remind’));

$result = $email->send();
$this->log(‘登録メール送信’.__FILE__.__LINE__);
} catch(Exception $e) {
debug($e->getMessage());
}
}
}

ですが、テンプレート指定や送信内容(POSTとかホストとか・・)は調べれば出てきます。

私がエラーで困っていた場所は、メールサーバーの部分で起きていた。

メールシステムの簡単なおさらい

 
どうやら開発で混乱している? ようなので……
 

ポート番号??

 
ポート番号ってのはTCP/IPに出てくる仕組みの一つで、
通信相手としてIPアドレスだけじゃなくてポート番号も指定することで
通信相手(プログラム)を特定する。
電話にたとえると家に掛けて『○○さんお願いします』と言うようなもの。
 
メールの送信(配送)に関係するポートはこの3つ
 
25 SMTP 通常のメール配送に使うポート メールサーバー間のメールのやり取りは今でもここが基本
587 submission SPAM対策で25番のかわりに使われるポート PCからサーバーにメールを渡すとき使う 通常は暗号化されないがオプションで暗号化も可能(STARTTLS)
465 SMTP over SSL 暗号化したSMTP通信を行うときのポート PCからサーバーにメールを渡すとき使う 常に暗号化される
 

サーバーどこ?

 
メールサーバー mail.parafamily.net
パラファミリー顧客の使うメール機能を一手に引き受けるサーバー
ポートは 25 587 465 が空いている
25 このサーバーで管理するメールアドレス宛のメールのみ受け取る
(ただしサーバー内部から接続して送信すると、外部サーバーへもメールを出せる)
465 SMTP認証が通った場合のみメールを受け取る
587 暗号化(STARTTLS)利用可能、SMTP認証が通った場合のみメールを受け取る
 
それ以外のサーバー(cs1とか)
これらのサーバーでもSMTPは動作しているが、送信専用である
25 サーバー内部からしか接続を受け付けない 外部サーバーへもメールを出せる
 
というわけで、WebシステムからSMTPでメールを出したい場合は、
localhost:25 へ接続してメールを出すのがよい。
(メールサーバーを経由しようとすると認証が必要なため面倒)

ここは処理とかじゃなく、メールサーバーも関係してくるので注意して欲しい。(泣)

========================================================

さて、ここで第一段階がおわりました。第二段階は送られたURLがリンクできるか、

パスワードと確認用パスワードが一致し、登録できるかの処理をいたします。

=========================================================

【UserController.php】 function reset_password(){}

// ハッシュのチェック ただしまだ完了フラグ(falseにする)は立てない
//ハッシュ文字列の情報があったら、Formから取得する
if(empty($in_hash) and !empty($this->request->data[‘User’][‘in_hash’])) {
$in_hash = $this->request->data[‘User’][‘in_hash’];
}
$user_id = $this->User->PasswordRemind->checkHash($in_hash, null, false); ・・・①
//$user_id = $this->User->getUserName($user_id);
if (empty($user_id)) {
throw new NotFoundException(__(‘Invalid Page’));
}
//↑↑↑↑Postデータが渡されるのは、パスワードと確認用パスワードなので、user_idは先に取得しておく必要がある。
// ポストデータがあれば保存をする(保存ボタンが押された場合以下の処理がはしる)
if ($this->request->is(‘post’)) {

$password = null;
$password_confirm = null;
if(!empty($this->request->data[‘User’][‘password’])) {
$password = $this->request->data[‘User’][‘password’];
}
if(!empty($this->request->data[‘User’][‘password_confirm’])) {
$password_confirm = $this->request->data[‘User’][‘password_confirm’];
}
$save = array(
‘id’ => $user_id,
‘password’ => $password,
‘password_confirm’ => $password_confirm,
);

$fieldList = array(
‘id’,
‘password’,
‘password_confirm’,
);

$this->User->id = $user_id;
//保存する
if($this->User->save($save,true,$fieldList)){
//保存成功したらハッシュを削除させるためにチェックを回す
$this->User->PasswordRemind->checkHash($in_hash);
$this->Session->setFlash(__(‘パスワードの更新に成功しました’));
// パスワード変更したんだから、ログイン画面がいいと思う
return $this->redirect(array(‘controller’ => ‘users’,’action’ => ‘login’));
}else{
$this->Session->setFlash(__(‘パスワードの更新に失敗しました’));
$errors = $this->User->validationErrors;

}
// これしちゃだめ→ unset($this->request->data[‘User’]);
} else {
// メールのURLからアクセスしたとき(POSTではない)
$this->request->data[‘User’][‘in_hash’] = $in_hash;
// 画面に$this->Form->hidden(‘in_hash’);を作る。
}
}

①ではcheckHashアクションで

================================================================

public function checkHash($hash, $time = null, $checking = true) {
if(empty($time)){
// 指定された時間がなければ
// 30分前の時間を取得
$time = date(‘Y-m-d H:i:s’, strtotime(date(‘Y-m-d H:i:s’) . ‘ -30minute’));
}
$hash = $this->find(‘first’, array(
‘fields’ => array(
‘PasswordRemind.id’,
‘PasswordRemind.user_id’,
),
‘conditions’ => array(
‘PasswordRemind.hash’ => $hash,
‘PasswordRemind.deleted’ => false,
‘PasswordRemind.created >’ => $time, //指定された時間よりも新しいhashの中で存在するかどうかのチェック
),
‘contain’ => array(),
));
// 存在すればUser_idを返し、存在しなければfalseを返す
if(!empty($hash[‘PasswordRemind’][‘id’])){
if($checking){
// checkingがtrueならば、同時に削除フラグを立てる
$savedata = array(
‘id’ => $hash[‘PasswordRemind’][‘id’],
‘deleted’ => true,
);
$this->save($savedata);
}
return $hash[‘PasswordRemind’][‘user_id’];
}else{
return false;
}
}

=============================================================

以上になります。第二段階のポイントはsave();ではなく、saveFields();関数で、

必要なデータやカラムを取得しているところとcheckHashアクションで保存前は、

削除フラグを立てず、保存した後に削除フラグをたてる(始めはfalseで、保存時にtrueにする)ところがポイントです。

テストケースの要点 Cakephp

テストケースは、開発したプログラミングに対して、意図しない動作をしないかを確認する作業です。

テストケースの書き方は

例えば

/Model/Articles.phpの
       * article名のみ取得する
public function getArticleName($article_id = null) {
$result = $this->find(‘first’, array(
‘conditions’ => array(
$this->alias.’.id’ => $article_id,
$this->alias.’.deleted’ => false,
),
‘fields’ => $this->alias.’.title’,
‘contain’ => array(),
));
return $result;
}

処理のテストケースを作成します。

===========================

補足

実行方法(teraterm)

・・・app]

全てのページを検証する場合

./Console/cake testsuite app AllTests

一つのページを検証する場合

./Console/cake testsuite app Model/Article

あるページの関数を検証する場合(debug(変数)等の中身おを調べたいとき)

./Console/cake testsuite app Model/Article –filter getArticleName(関数名)

==================================

検証する論理値(仮定しなければいけないこと)

実行する処理(今回は記事のタイトルを取得する)に対して、仮定することはいくつかあります。

①id(個人データ)があったら、そのタイトル名(Articleのtitle)を取得できるか

②削除済みのタイトルは取れない

③存在しないタイトルは取れない場合(削除されていない場合)

【実際のテストケース】

Model/Article.php

/**
* testGetTheAge method
*
* @return void
*/
public function testArticleName(){
// 存在しないタイトルは取れない
$result = $this->Article->getArticleName(99999999);
$compare = array(); //debug($result)
$this->assertEquals($compare, $result);
// 削除済みのタイトルは取れない
$result = $this->Article->getArticleName(6);
$compare = array();
$this->assertEquals($compare, $result);
// タイトルが取れる 
$result = $this->Article->getArticleName(3);
$compare = array(
‘Article’ => array(
‘title’ => ‘うぁーがんばろー’,
)
);
$this->assertEquals($compare, $result);
}

======================

【補足②】

始めに

@return void(->何も返さないよ) とか

@return array(->配列の返すよ)

など、返り値を設定しておきます。

*deletedの考え方

deleted = 削除済みのものを取ってくる

type P = false =>0、true=>1

*debug()関数に関して

debug()関数は取得したいデータを取ってきたい場合

実行したときにそのデータ処理が取得できます。

 

======================

Fixture(テストケースのデータ格納場所)の追加に関して

Fixtureに情報(データ)を格納したら、AllTestsをするとき、

そのときにでたエラーを修正していきます。

========================

このように、実行したい処理が何をしている処理なのか

(データを取得したいのか、削除したデータを取ってきたいのか、IF文で別々に処理しているのか、空の場合の処理なのか)

など、考えた上で、

テストケースは10パターンほど考えます。多ければ多いほどよいです。

このようにもし何かの不具合が見つかったら、何処が悪かったのかを検証できるので

基本的なことですがしっかりと見につけていけたらいいですね。

CAKEPHP nl2br() に関して

nl2br ・・・・・ 改行文字の前に HTML の改行タグを挿入する関数です。

書式:string nl2br( string string )

nl2br()は指定された文字列に含まれる全ての改行文字(\nなど)の前に、HTMLの改行タグ(<br />など)を挿入します。改行文字とは、行の最後に挿入して、そこで行を変えることを示す制御文字の一種である。ソフトによっては、矢印などを表示する場合があるが、通常、改行文字は目に見えない。

改行文字としては、キャリッジリターン(CR)、ラインフィード(LF)、この2つを連続したものなどが使用される。UNIX系OSではLF、Macintosh系ではCR、Windowsやインターネット電子メールはCR+LFが標準となっている。

返り値:改行文字の前にHTMLの改行タグを挿入した文字列を返します。

<?php

$str = 1行目\n2行目;

print nl2br($str);

?>

出力結果

1行目
2行目

get_template_directory_uriとget_stylesheet_directory_uri の違い

get_template_directory_uri()はWordPressテーマディレクトリまでのURLを取得する関数です。

もう一方で、

get_stylesheet_directory_uri()はWordPressテーマディレクトリまでのURLを取得できる関数です。

違いは、WordPressテーマの親子関係にあります。

get_template_directory_uri()をもう少し細かくいうと、親テーマで使用した場合は、get_stylesheet_directory_uri()と変わらずに有効化してあるWordPressテーマのテーマディレクトリURLの取得します。小テーマで使用した場合は、子テーマのstyle.cssに書かれている「Template」をみてテーマディレクトリURLを取得しています。

もし、子テーマを指定し、そこからURLを取得する場合は、get_template_directory_uri()とget_stylesheet_directory_uri()が違います。get_template_directory_uri()は親テーマのテーマディレクトリURLを出力してくれますが、get_stylesheet_directory_uri()は子テーマのテーマディレクトリURLを出力してくれます。

<まとめ>

get_template_directory_uri()とget_stylesheet_directory_uri()の違いについて紹介しました。WordPressのテーマ開発をするときはget_template_directory_uri()は親テーマで使い、get_stylesheet_directory_uri()子テーマで使うといった感じに分けるといいでしょう。

 それでは・・・

findメソッドの引数

findメソッドは、sqlでいうselect文にあたるメソッドです。その名の通りデータの検索を行います.  メソッドに引数を与えて,処理を色々と変えてきます。

【find関数の引数について】

第1引数

  • find(‘all’) : 条件に該当するデータ全てを取得します.
  • find(‘first’) : 条件に該当するデータの最初の1レコードを取得します.
  • find(‘list’) : 条件に該当するデータをidとラベルが対になった形で取得します.
  • find(‘count’) : 条件に該当するデータの件数を取得します.

*条件を指定しない場合は,これだけでも利用できます

第2引数

  • conditions : データの検索条件を指定します.すごくよく使うので後述します.
  • fields : どのフィールドのデータを取得するかを指定します.
  • order : ソートの仕方を指定します.
  • limit : データを取得する件数を指定します.
  • offset : データ検索を何件目から行うかを指定します.

*よく使うのはcondisions(where句に相当する), order(order by句に相当する),limit(limit句に相当する)の三つだと思います.

condisionsの書き方について

array(
‘conditions’ => array(
     ‘モデル名.id’ => 1
}
}
というような形で記述すれば良いです.
public function index(){
            $this->set(‘data’,$this->Board->find(‘first’,array(
                ‘conditions’ => array(‘Board.id’ => 48))
                ));
        }
という感じで記述するとidが48のものを取得します.find(‘first’)を使ってますが,idが48のデータは1つしかありえないので,firstで一件だけ取得する書き方の方が効率的です.
メインのfind関数以外にも、たくさんのコントローラーメソッドがあります。それらはまた次回にします。

IF文とSWITCH・CASE文の使い分け

ある条件を調べて処理を切り替えるには、ifとswitch caseの2つの方法があります。

条件判定と分岐の基本はifです。switch caseは1つの値を順次比較して比較元と比較先が『等しい』ときだけ処理の流れを切り替える──という形で、ifの構造を単純化した変形と捉えればいい。

switch文の基本用法

switch( 変数や式 ){
  case 値1:
  処理1;
      break;
  case 値2:
  処理2;
      break;
  default:
  デフォルトの処理
}

 

IF文を使用した場合

<?php
$a = 2;
if( $a == 0 ){
  echo '$aは0です。';
}
else if( $a == 1 ){
  echo '$aは1です。';
}
else if( $a == 2 ){
  echo '$aは2です。';
}
else{
  echo '$aは0・1・2のいずれでもありません。';
}
?>

SWITCH・CASE文を使用した場合

<?php
$a = 2;
switch( $a ){
  case 0:
      echo '$aは0です。';
      break;
  case 1:
      echo '$aは1です。';
      break;
  case 2:
      echo '$aは2です。';
      break;
  default:
      echo '$aは0・1・2のいずれでもありません。';
}
?>

どちらも出力結果は【$aは2です。】です。

SWITCH文で重要なのは、case文以降breakです。breakがなかったら、条件が成立したcase文以降のcaseも実行しちまいます。

使い分けとしては、処理構造に適した構文をつかえ。です。

たくさんの比較先から1つの値と等しい1つだけを見付けたい場合、switch caseの方が遙かに有効です。switch caseを使った──ソース上で“switch”というキーワードを見た時点で、『1つの変数を順次比較している』という構造だとすぐに理解できるからです。

以上このお話はおわり。

CakePHP:find関数;nullってなに?<IS NULL>と<NOT NULL>の書き方

初心者にはなかなか理解しづらい「null」。

そもそも「null」とは、

「NULLは特殊な値です.NULLは 「列名 = NULL」 や 「列名 <> NULL」 といった通常の比較演算子を用いた方法では検索することができません. NULLを対象として検索するにはIS NULL演算子,もしくはIS NOT NULL演算子を使用します.」

そして、

NULL値はデータが存在しないことを表す値です。大文字と小文字のどちらも使用できます。

NULLはデータが存在しないということなので、文字列における空文字”や数値における0とは異なります。

プログラムで使う変数は宣言をした時に領域が確保されます。

そのあと、変数が持っているアドレスが0.0.0.0の状態がnullです。

あ。これはちょっと広義的になってしまうので・・・・説明はここまでで・・・・

現在、CakePHPでプログラミングをしているので、

今回は

CakePHPのfind条件に「null」「not null」を使う方法を記述しておきます。

上記で記述したとおり、「NULLを対象として検索するにはIS NULL演算子,もしくはIS NOT NULL演算子」を使用すると書きました。これはそれぞれ書き方が違います。

<IS NULL>の場合

$data = $this->Model->find( 'all',
    array(
        'conditions' => array('Model.id' => NULL),
        'fields'     => null,
        'order'      => null,
        'recursive'  => 1,
    )
);

SQLでいうところの、IS NULL の方法。
単純に、 conditions に配列で指定するだけです。

これで WHERE Model.id IS NULL というSQLとなります。

<NOT NULL>の場合

NOT NULL の場合は、ちょっとだけひねって、”NOT”の2次元配列で条件を作成。

$data = $this->Model->find( 'all',
    array(
        'conditions' => array(
            'NOT' => array(
                'Model.id' => NULL)
        ),
        'fields'     => null,
        'order'      => null,
        'recursive'  => 1,
    )
);

カラムにNULL値を持つ事が出来ないように設定する方法になり、

これで、WHERE Model.id IS NOT NULL というSQLとなります。

とりあえずここまでにしますのが、

あと基本的に書き方が同じなfind条件での「IN」、「NOT IN」演算子の使い方については次回にしたいと思います。

 

それでは。。

第一回PostgreSQL

PostgreSQLとは、データベースを管理するために使われるリレーショナルデータベース(RDB)管理システムです。また、オープンソースなため、世界中で使われているRDBです。

初心者が覚えるべき最低限の用語~概念を理解しよう~

概念:スキーマ:プログラミング手法における論理構造や物理構造を定めた仕様です。

似ているものに[mysql]がありますが、

[mysql]は

データベース → テーブル

[PostgreSQL]は

データベース → [スキーマ] → テーブル

と論理構造が違います。

select文とかcreate,where,delete文等は同じです。

しかし、[PostgreSQL]はスキーマ名を記入する必要があり、ドットでスキーマ名とテーブル名を記入しなければいけません。

例)

mysql
SELECT * FROM db_table;

【postgres】
SELECT * FROM schema_name.table_name;

まずはまずはまずは!、これだけ覚えておけば大丈夫でしょう。

次回はいくつかのコマンドを紹介したいと思います。

Bootstrap ②正しい使い方とポイント

<グリッドシステム>

Bootstrapのグリッドデザインは、基本的に横幅940px(固定エリア12グリッドにあわせる)の中に段組をする必要があります。しかし、複雑な段組をする場合は少し注意点があるので簡単に記しておきます。

ポイント1

・グリッドシステムで複雑な段組をするなら、

container => row => col => row => col と入れ子にする。

<div class=”container”>

   <div class=”row”>

      <div class=”col-{prefix}”></div>

    </div>

</div>

*row が何段目であっても、配下のcolの幅が合計は12グリッドである。

ポイント2

コンテンツはcontainerクラスかcolクラスの内部に記述するようにすること。rowの中には書いてはいけません。

注意点:spanはBootstrap 2系では使えませんので覚えておきましょう。

 

それでは・・・