カテゴリーアーカイブ PHP

村上 著者:村上

【PHP】配列で重複した値を削除する方法

たまにしか使わないから毎回忘れる配列の値が重複したときの削除方法について。
今回使用するのは、array_unique という関数です。
PHPのマニュアルページはこちらから。

PHP: array_unique – Manual
http://php.net/manual/ja/function.array-unique.php

 

こちらの関数は、重複を削除したい配列を引数として渡せば、重複を削除した後の配列を戻り値として返してくれます。
サンプルコードは下記のとおりです。

$array = array(1, 3, 5, 1, 2, 4, 3);
// 重複削除
$unique = array_unique($array);

// 実行結果:array(1, 3, 5, 2, 4)

ただし、この関数では、重複削除後もキーは保持されます。
なので、詳細に書くと結果が下記のようになっていることに注意してください。

$array = array(0 => 1,
               1 => 3,
               2 => 5,
               3 => 1,
               4 => 2,
               5 => 4,
               6 => 3);
// 重複削除
$unique = array_unique($array);

// 実行結果:array(0 => 1,
//                1 => 3,
//                2 => 5,
//                4 => 2,
//                5 => 4);

結果を単に foreach かなにかで処理するだけなら問題ないかと思いますが、キーをセットに扱う処理を行う場合などは、このままでは使えません。
その場合は、PHPの関数の array_values を使います。
こちらを使うと、数字が飛び飛びになったキーの番号を振り直すことができます。
使用方法はこちら。

$array = array(0 => 1,
               1 => 3,
               2 => 5,
               3 => 1,
               4 => 2,
               5 => 4,
               6 => 3);
// 重複削除
$unique = array_unique($array);
// キーの振り直し
$result = array_values($unique);

// 実行結果:array(0 => 1,
//                1 => 3,
//                2 => 5,
//                3 => 2,
//                4 => 4);

これでキーの番号が飛び飛びになる問題も解決できます。

 

ということで、配列のデータ重複を解消する方法でした。
意外と使う機会がある関数なので、覚えておいて損はないはず。
ついでに、下の方で紹介した配列のキーの振り直し方法についてもセットで覚えておくといいでしょう。

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

Zend Framework1 Zend_Mail+PHP5.6ではSSLのチェックが無効化できない

既にサポートの終わったZendFramework1ですが、今使っている方は注意が必要かもしれません。

ZendServer8.5 for IBM i(PHP5.6)を入れて・・・ – ushidayの日記

PHP5.6から、CA証明書のチェックがデフォルトで必須の設定になったようなのですが、
これによって何も指定を行っていない場合、PHPからSMTPS経由でメールを送る場合は接続先SMTPサーバーのSSL証明書が”正しい”物でないと接続に失敗します。

なお、この設定は変更することが可能ではあるのですが、

SSL コンテキストオプション – php.net
調べた限りでは、使用するメールライブラリがSSL コンテキストオプションの”verify_peer”の指定に対応していないと設定変更が難しいようなのです。
Zend Framework1のZend_Mailではこのオプションの指定をサポートしていないため、PHP5.6上で動作させると、強制的にSSL証明書のチェックが有効となります。

ちなみに、Zend Framework1のZend_MailのSSLコンテキスト対応化は行われないことはZend Framework1のGitHubフォーラムで明言されています。

Zend_Mail SMTP SSL Problem with PHP 5.6 – GitHub

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

【PHP】empty()関数で空と判断される値

そう言えば、ちゃんと調べたことがなかったのでまとめ。

変数に値が格納されているかのチェックをするために用いる empty() 関数ですが、「空の変数」だと判断される値は下記の8つです。

  • “” (空の文字列)
  • 0 (整数 の 0)
  • 0.0 (浮動小数点数の 0)
  • “0” (文字列 の 0)
  • NULL
  • FALSE
  • array() (空の配列)
  • 変数は宣言されているが、値が指定されていない変数

PHPマニュアルを参考にさせていただきました。

PHP: empty – Manual
http://php.net/manual/ja/function.empty.php

調べるまでもなく、大体把握していた通りでしたが…文字列の「0」も「空」だと判定されるのは実際にやったことがないので知りませんでした。
なお、指定した変数が存在していなくてもエラーにはならないとのこと。

また、似ている関数に isset() 関数があります。
こちらは、変数が宣言されており、かつ値がNULLでなければ true を返します。
…が、こちらはあまり使わないかな?

 

ということで、empty()関数についてでした。
意外と今までの経験から「多分こんな感じ」で把握しているだけだったので、こうして改めて調べるのも大事ですね。

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

【PHP】TwitterOAuthライブラリを使って登録したメールアドレスを取得する方法

タイトル通り、TwitterAPIを使ってTwitterからメールアドレスを含むユーザー情報を取得する方法についてです。
ちょっとだけ面倒だったので、備忘録としてまとめ。

使用するのは、TwitterOAuthというPHPのライブラリです。
下記の公式サイトから、インストールから導入方法まで記載されています。

TwitterOAuth PHP library for the Twitter REST API
https://twitteroauth.com/

 
Twitter Application Management 側の設定は割愛します。
が、アプリを作成時、パーミッションの項目で「Request email addresses from users」にチェックを入れるのだけは忘れずに。
Twitter Application Managementには下記からアクセスできます。

Twitter Application Management
https://apps.twitter.com/

 

さて本題のメールアドレス取得ですが、コードは下記のとおりです。

$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, $access_token, $access_token_secret);
$content = $connection->get("account/verify_credentials",array('include_entities'=> 'false', 'include_email'=> 'true'));

CONSUMER_KEYCONSUMER_SECRETは、Twitter Application Management でアプリを作成すると自動で生成されるので、そちらを使用します。
$access_token と $access_token_secret は、Twitterのアカウント連携が許可されたときに取得できました。
私の場合、こちらの連携処理は、CordovaのTwitter-connect-plugin を使用して取得したトークンを使っています。

TwitterOAuthを新しく定義した後、getメソッドに「account/verify_credentials」と指定します。
が、このままではメールアドレスは取得できないため、オプションのパラメーターとして「array(‘include_entities’=> ‘false’, ‘include_email’=> ‘true’)」を指定します。
include_email = true」という指定がメールアドレス取得に関係していて、これで無事にメールアドレスを含むユーザー情報を取得できます。

なお、取得したデータはオブジェクトのため、そのままで扱いずらい場合は、配列にします。
この時、下記のように 一度JSON形式にした後、さらに JSONを配列にすれば、扱いやすい形になります。

// オブジェクト→JSON→配列に
$user = (json_decode(json_encode($content), true));

以上、Twitterアカウントのメールアドレスを取得する方法でした。
ただ個人的には、TwitterOAuthの使い方と同じくらい、オブジェクト→配列の処理が便利だと感じましたね。
皆様も是非ご活用ください。

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

【PHP】リンク先のURLが有効かどうかを確認する方法

画像のURLを扱うときに、もしそのURLがリンク切れだったら代わりの画像を表示させる、という処理を行いたかったので、その方法についてまとめ。

なお、今回はこちらのサイトを参考にさせていただきました

【php】 URLが存在するかどうか確認する at softelメモ
https://www.softel.co.jp/blogs/tech/archives/4766

 

チェック方法としては、下記のように file_get_contents 関数を利用して、URL先のサイトの内容を文字列に読み込み、結果が返ってくればリンク先が存在している、という判断をしています。

$url = 'チェックしたいリンク先のURL';
$response = @file_get_contents($url, NULL, NULL, 0, 1);
if ($response !== false) {
    // リンク先が存在するときの処理
} else {
    // リンク先が存在しない時の処理
}

が、すべての内容を取得すると処理が重くなってしまうため、先頭の1文字だけを取得しています。
また、file_get_contentsは、リクエスト先がないときに warning が発生してしまうので、@をつけてエラーメッセージを表示させないようにしています。

 

他にも fopen 関数や get_header 関数を使用する方法も載っていましたが、これが一番処理が早く、また分かりやすいかなと思います。
URLチェックをしたい場合は、是非参考にしてください。

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

PHPでお手軽にセッションハイジャック対策をする方法

皆さんはセッションというのをご存知でしょうか。
各クライアント(ブラウザ)に対して、サーバーからセッションIDという一意の識別番号を発行してクライアントに保存することで、個々のクライアントを識別できるようにする仕組みです。

Webサービス上では、ログイン状態の管理や、ユーザー情報の一時保存などによく使われます。

このセッションIDですが、実態はブラウザ側にCookieとして保持されているため、もし何らかの方法で不正に抜き取られてしまうと、場合によってはアカウント乗っ取りなどをされてしまう可能性があります。
このような攻撃を一般的に”セッションハイジャック”と呼びます。

対策としてセッションIDを定期的に変更することで、こういった不正ログインを簡単に防ぐことができます。

具体的には、
“session_regenerate_id()”
関数を実行することで、セッションを維持したままセッションIDを更新することが可能です。

session_regenerate_id() – PHP.net Documentation

例えばこの関数をログインチェック時や、特定、あるいはすべてのページにアクセスされたときに実行されるようにしておけば、万が一セッションIDを盗み出されても、不正ログインされる確率が低くなります。

また、

“session_regenerate_id(true)”

とすると、セッションを切ったうえでセッションIDを再発行できるので、ログイン状態はリセット(ログアウト)されてしまいますが、よりセキュアな状態にすることも可能です。

年々、Webサービスへの攻撃手法が高度化してきていている一方で、アプリの設計などにより基本的な脆弱性が発生してしまうこともまだまだあるようです。
高度な攻撃への対策は高度な知識とテクニックが必要になることもありますが、基本的な対策は知っていればだれでも対策できることも多いので、是非押さえておきたいですね。

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

【PHP】PHPExcelでグラフを一から作る方法

昨日もPHPExcelについての記事を書きましたが、本日も引き続き同じネタについてまとめ。
当初はグラフ入りテンプレートを使ってグラフを描写する予定でしたが、思っていた以上に「複雑なグラフ」のボーダーラインが低く、どうしても作りたいグラフが消されてしまうので、プログラムでグラフ作成をすることにしました。

 

ライブラリ導入から、現在のシート選択の部分は割愛します。
やっていることは意外と単純で、まず、グラフの表示範囲や参照先のセルを指定します。

//グラフ描画設定
$options = [
    'title' => 'グラフタイトル',
    'topPos' => 'A3',   //描画するグラフの左上の位置
    'bottomPos' => 'I24',   //描画するグラフの右下の位置
    'labelPos1' => $sheet.'!$B$2',  //グラフのデータラベル
    'xAxisRange' => $sheet.'!$A$3:$A$12',   //グラフのx軸の値の範囲
    'dataValueRange1' => $sheet.'!$B$3:$B$12'  //実際のデータ範囲
];
なお、$sheet は、現在アクティブなエクセルのシートを指定します。

実際にグラフを書いているのは下記のコード。

// グラフのデータラベル設定
$dataSeriesLabels = [
    new PHPExcel_Chart_DataSeriesValues('String', $options['labelPos1'], null, 1)
];

// グラフのX軸項目設定
$xAxisTickValues = [
    new PHPExcel_Chart_DataSeriesValues('String', $options['xAxisRange'], null, 10)
];

// グラフの系列設定
$dataSeriesValues = [
    new PHPExcel_Chart_DataSeriesValues('Number', $options['dataValueRange1'], null, 10)
];

//  グラフ描画設定
$series1 = new PHPExcel_Chart_DataSeries(
    PHPExcel_Chart_DataSeries::TYPE_BARCHART,               // 横棒グラフ
    PHPExcel_Chart_DataSeries::GROUPING_CLUSTERED,          // plotGrouping
    range(0, count($dataSeriesValues)-1),                  // plotOrder
    $dataSeriesLabels,                                     // plotLabel
    $xAxisTickValues,                                      // plotCategory
    $dataSeriesValues                                      // plotValues
);
$series1->setPlotDirection(PHPExcel_Chart_DataSeries::DIRECTION_BAR);

//  プロットエリアの設定
$plotarea1 = new PHPExcel_Chart_PlotArea(null, [$series1]);
//  グラフ内での凡例のポジション設定
$legend1 = new PHPExcel_Chart_Legend(PHPExcel_Chart_Legend::POSITION_BOTTOM, null, false);
//  y軸のラベル設定
$yAxisLabel1 = new PHPExcel_Chart_Title('');
//  タイトルがある場合、タイトルの設定
$title1 = new PHPExcel_Chart_Title($options['title']);

//  グラフ作成
$chart1 = new PHPExcel_Chart('chart1',       // グラフの名前
                             $title1,        // グラフタイトル
                             $legend1,       // 凡例
                             $plotarea1,     // グラフのプロットエリア
                             false,           // 表示されているセルだけをプロット
                             0,              // 空白セルをどうするか
                             null,           // x軸のラベル
                             null            // y軸のラベル
);

//  グラフがワークシートのどこに描画されるかの設定
$chart1->setTopLeftPosition($options['topPos']);
$chart1->setBottomRightPosition($options['bottomPos']);

//ワークシートにグラフの追加
$objWorksheet->addChart($chart1);

こちらのコードでは横棒グラフを作成しています。
表示位置やタイトルを任意で決められるので、なかなか自由度は高めですね。

 

作成できるグラフの種類も豊富で、棒グラフ以外にも、折れ線グラフやレーダーチャート、あとは設定名的に察するに、バブルチャートなんかも使えそうでした。
…が、よく使うのは棒グラフ・折れ線グラフ・円グラフぐらいかな。

便利&簡単なPHPExcelですが、若干ハマっている箇所もあり、どうしても縦軸の項目名とグラフの凡例が正しく表示されません…。
データ自体は指定してあるので、設定が間違っているのだと思っています。
もし、この不具合がわかる方いらっしゃいましたら、どうぞコメントでご指摘をお願い致します。

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

【PHP】PHPExcelでグラフ入りのテンプレートを使用する方法

以前、「【PHP】PHPExcelを使うときにセルの書式設定を変更する方法」という記事を投稿しましたが、本日の記事は、またこの PHPExcel について。
今回は、PHPExcelでテンプレートファイルを使う際に、グラフが入っていた場合の処理についてまとめです。

今回参考にした投稿はこちら。

PHPExcelでテンプレートファイルからグラフを作ってみよう – Qiita
https://qiita.com/tutida/items/2d163ed7662bb499a082

やりたいことがすべて書いてありました…!

 

早速、コードを書いていきますが、PHPExcelオブジェクト生成から、シートの選択まではこんな感じ

// PHPExcelオブジェクトを生成する
$book = new PHPExcel();
$objReader = PHPExcel_IOFactory::createReader('Excel2007');
// 読み込むテンプレートファイルにグラフが含まれていることを宣言
$objReader->setIncludeCharts(TRUE);
// テンプレート読み込み
$book = $objReader->load('テンプレートのエクセルファイルのパス');
$book->setActiveSheetIndex(0);
// カレントシート選択
$sheet = $book->getActiveSheet();

上記のコードで重要なのは、5行目の「読み込むテンプレートファイルにグラフが含まれていることを宣言する」、という

$objReader->setIncludeCharts(TRUE);

上記の記述です。
この一行を入れないと、読み込んだテンプレートファイルからグラフが消えてしまいます。

また、読み込み時だけでなく、下記のようにエクセルファイルの出力・保存の時にも同じ記述を入れる必要があります。

// ファイル名
$filename = 'PHPExcel-sample.xlsx';
$writer = PHPExcel_IOFactory::createWriter($book, 'Excel2007');
// 書き出すエクセルファイルにグラフが含まれていることを宣言
$writer->setIncludeCharts(TRUE);
$writer->save("/tmp/".$file);
File::download("/tmp/".$file, $file);

こんな感じ。
出力時にも、エクセルファイルにグラフが含まれていることを宣言する5行目の記述を必ず入れましょう。

 

ただ、グラフを扱う際には注意が必要で、あまり複雑な指定をすると、グラフが含まれていることを宣言していてもグラフが消える場合があります。
現に、私もそれで悩まされています。
グラフ入りのテンプレートを入れる場合は、極力簡単でシンプルなものを使うようにしましょう。

なお、グラフが消える・簡略化される条件は下記のようなものがあげられるとのこと。

  • X軸を設定している
  • Y軸を2種類設定している場合、2つ目は消える
  • 詳細な設定はほぼ消える

…かなり簡単なものしか扱えなさそうですね。
これならいっそ、テンプレートから読み込まず、PHPExcelでグラフを作成したほうがいいかもしれません。

ゼロからグラフを作成する方法については、冒頭で挙げた投稿を書かれた方が記事を挙げているので、こちらが参考になるかと思います。

PHPExcelでゼロからグラフを書いてみよう – Qiita
https://qiita.com/tutida/items/643baa8832beedd53499

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

【PHP】DateTimeで現在日時から○日後の日付を取得する方法

後輩に聞かれたので、私と彼のための覚え書きのメモとして。

PHPには、日付と時刻を扱う DateTimeクラスがありますが、こちらを用いて、現在の日時から○日後や、○時間前の日付・時刻を取得する方法です。

DateTimeクラスについて、PHPのマニュアルはこちらから。

DateTime クラス – Manual
http://php.net/manual/ja/class.datetime.php

 

○日後を扱う前に、まず現在の日時を取得する方法は下記の通り。

// 現在の日時を取得
$now = new DateTime();
echo $now->format('Y-m-d H:i:s'); // 2017-12-05 19:05:00

DateTimeの引数を空で指定すると、現在の日時を取得できます。
それを任意のフォーマットに変換しています。

また日付文字列を引数に指定する事も出来ます。

// 日付文字列で指定した日時を取得
$date = new DateTime("2017-06-01 06:00:00");
echo $date->format('Y-m-d H:i:s'); // 2017-06-01 06:00:00

日付文字列で指定した日時を取得できます。

 

で、本題はここから。
○日後という相対的な日時を取得したい場合、modify というものを使うことにより、DateTimeで取得した日付を変更できます。

// 現在の日時の1日後の日時を取得
$date = new DateTime();
$date->modify('+1 day');
echo $date->format('Y-m-d H:i:s');  // 現在の日時の1日後の日付

または、この書き方でもOK。

// 日付文字列で指定した日時の1日後の日時を取得
$date = new DateTime("2017-06-01 06:00:00 + 1 day");
echo $date->format('Y-m-d H:i:s'); // 2017-07-01 06:00:00

上記はGoogle Chromeでしか動作検証していませんが、1日後の日付が正しく取得できました。

それ以外にも、「– 1 day」と書けば1日前、「+ 3 hour」と書けば3時間後、「+ 1 week」と書けば1週間後の日時がそれぞれ取得できます。
日付の変更は、使用頻度はそこまで高くはないのですが、ふとした拍子に使ったりするので、頭の片隅ででも覚えて置きたいですね。

 

また、今回 DateTimeクラスを調べていて知ったのですが、数値を指定して日時を取得することもできるとのこと。
このやり方については私はまだ実際に使ったことありません。

// 数値を指定して日時を取得
$date = new DateTime();
$date->setDate(2017,6,1);
$date->setTime(6,0,0);
echo $date->format('Y-m-d H:i:s'); // 2017-06-01 06:00:00

セレクトボックスから年・月・日をそれぞれ選んで、それらを日付に変換するときとかに使えそうですね。
が、今回はDatepickerを使っているので、使うことはなさそうです。

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

【未解決】FuelPHPでストアドプロシージャを実行してデータを取得したい

タイトルにある通り、今回の記事はまだ未実装、というか実現できていないことについて。
ということで、もし解決策をご存知の方がいらっしゃれば、何卒ご教授くださいますようお願い致します。

 

ストアドプロシージャについては、こちらの記事がわかりやすいかと。

ストアドプロシージャの基本的ななにか – Qiita
https://qiita.com/setsuna82001/items/e742338eb93e3a48ba46

こちらの記事によると、ストアドプロシージャとは「データベース上での一連の処理に、名前をつけて関数のように呼び出して使用できるもの」とのこと。
データベース上で動作が完結するので、開発言語に依存しません。

 

FuelPHPについて、公式サイトはこちらから。

FuelPHPドキュメント
http://fuelphp.jp/docs/1.7/

FuelPHPは、PHP5.3以上を対象に開発されたWebフレームワークです。
他のフレームワークに比べて規約が少なく、また高速で軽量なため、使いやすいのが特徴です。

こちらのサイトもご参考に。

高速で軽量なフレームワークFuelPHPを使う
http://www.buildinsider.net/web/bookphplib100/096

 

そして、今回実現したいのは、この両方を利用して、データベースからデータを取得する方法についてです。
実行するストアドプロシージャはこんな感じ。

1> EXEC dbo.user_month_report @year =2017, @month =12;
2> go

※実際に動作させているものとは異なります。

こちらをターミナルで実行すると、望んだとおりの結果が得られます。
したがって、ストアドプロシージャ自体には問題はなさそう。

が、こちらを下記のように FuelPHP で実行すると、結果が何故か bool(true) が返ってきます。

$result = DB::query("EXEC dbo.user_month_report @year =2017, @month =12;");
$result->execute();

ストアドプロシージャに問題がないようなので、十中八九 FuelPHP が原因というのは分かるのですが、その解決策がどうしてもわかりません。
FuelPHPのドキュメントにも、ストアドプロシージャの実行方法についての記述がないため、そもそも対応していないのでしょうか。

ちなみに、FuelPHPのフォーラムに、「DB Class with mysql – select from stored procedure」という、今回の状況に似たような投稿があったのは見つけました。
その中で、DB::query()の第二引数の$typeに SQL クエリタイプとして「DB::SELECT」を指定するといいとの記述があったので試してみましたが、残念ながら結果は変わりませんでした。

参考にしたフォーラムの投稿はこちら。

DB Class with mysql – select from stored procedure
https://fuelphp.com/forums/discussion/4299

 
新しいライブラリやフレームワークを使うのは、やはり難しいですね。

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