require, require_once

require は同じファイルを何度も取り込む
require_once は一度だけ取り込む
インクルードファイルがない場合、Fatal errorとして処理を中断

include, include_once
Warningを出力し、処理を継続

sample
ini.php

<?php
echo "お客様の信用取引の委託保証金状況(概算)により、追加保証金(追証)の状態となっております。 <br>"
?>

index.php

<?php
require("in.php");
require("in.php");
require("in.php");
?>

require_onceに変更します。
index.php

<?php
require_once("in.php");
require_once("in.php");
require_once("in.php");
?>

github AOuth2

_config.php

<?php
require_once './vendor/autoload.php';
session_start();
$github_keys = require('./github-app-keys.php');
$provider = new League\OAuth2\Client\Provider\Github(&#91;
	'clientId' 		=> $github_keys['clientId'],
	'clientSecret'	=> $github_keys['clientSecret'],
]);

$title = "PHP GitHub Login Sample";

github-app-keys.php

<?php
return &#91;
	'clientId' => 'xxxx',
	'clientSecret' => 'xxxxxxxx'
];

login.php

<?php
require_once '_config.php';

$authUrl = $provider->getAuthorizationUrl();

$_SESSION['oauth2state'] = $provider->getState();

header('Location: '.$authUrl);
exit;

callback.php

<?php
require_once '_config.php';

if (empty($_GET&#91;'state'&#93;) || ($_GET&#91;'state'&#93; !== $_SESSION&#91;'oauth2state'&#93;)){
	unset($_SESSION&#91;'oauth2state'&#93;);
	exit('Invalid state');
}

$token = $provider->getAccessToken('authorization_code', [
	'code' => $_GET['code']
]);

echo $token.'\n';
echo 'Successfully callbacked!!'.'\n';

$user = $provider->getResourceOwner($token);

echo '<pre>';
var_dump($user);
echo '</pre>';
[vagrant@localhost api]$ php -S 192.168.33.10:8000

github AOuth

まずComposerを入れます。

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

composer.jsonの作成

$ php composer.phar init
[vagrant@localhost api]$ ls
composer.json  composer.phar  google-api-php-client
[vagrant@localhost api]$ sudo mv composer.phar /usr/local/bin/composer

GitHubでApplicationをregisterして、Client IDとClient Secretを取得します。
https://github.com/settings/developers

composerで入れます。

[vagrant@localhost api]$ composer require league/oauth2-client league/oauth2-github
Using version ^2.3 for league/oauth2-client
Using version ^2.0 for league/oauth2-github
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Package operations: 7 installs, 0 updates, 0 removals
  - Installing paragonie/random_compat (v2.0.11): Downloading (100%)
  - Installing guzzlehttp/promises (v1.3.1): Downloading (100%)
  - Installing psr/http-message (1.0.1): Downloading (100%)
  - Installing guzzlehttp/psr7 (1.4.2): Downloading (100%)
  - Installing guzzlehttp/guzzle (6.3.0): Downloading (100%)
  - Installing league/oauth2-client (2.3.0): Downloading (100%)
  - Installing league/oauth2-github (2.0.0): Downloading (100%)
paragonie/random_compat suggests installing ext-libsodium (Provides a modern crypto API that can be used to generate random bytes.)
guzzlehttp/guzzle suggests installing psr/log (Required for using the Log middleware)
Writing lock file
Generating autoload files
[vagrant@localhost api]$ ls
composer.json  composer.lock  google-api-php-client  vendor

foreach loop sample2

We have an associative array that stores name and yield.

<?php
$yield = array(
	"レカム"=> "16,776,900",
	"JALCOホールディングス"=>"15,380,900",
	"明豊エンタープライズ"=>"12,639,200",
	"石垣食品"=>"5,372,100",
	"ネクストウェア"=>"5,073,400"
);

foreach( $yield as $key => $value){
	echo "銘柄: $key, 出来高: $value<br>";
}
?>

foreach文

指定した配列に関してループ処理を実行。各ループ時には、現在の要素の値が変数$valueに代入され、配列ポインタが1つ進められる。

foreach文の使用例

foreach (配列 as value)
 ループ処理

サンプル

<?php
$a = array(
	1 => 1,
	2 => 4,
	3 => 9,
	4 => 16
);

foreach( $a as $value){
	echo $value."<br>\n";
}
?>

拡張構文
各ループで、要素の値が$valに、要素のキーが変数$valに代入される。

foreach(配列 as $key => $val)
 ループ処理;

サンプル

<?php
$body = array(
	"head" => "頭",
	"nose" => "鼻",
	"face" => "顔",
	"hand" => "手"
	);

foreach( $body as $key => $value){
	echo $key. ":" .$value."<br>\n";
}
?>

多次元配列の出力

<?php
$code = array(
	"Mothers"=> array(
		"ブライトパス・バイオ"=> "4594",
		"ジーエヌアイグループ"=> "2160",
		"アンジェス"=> "4563",
		"ナノキャリア"=> "4571"
		),
	"JASDAQ"=> array(
		"レカム"=> "3323",
		"JALCOホールディングス"=> "6625",
		"明豊エンタープライズ"=> "8917",
		"石垣食品"=> "2901"
		)
);

foreach( $code as $key1 => $val1){
	echo "--".$key1. "--<br>\n";

	foreach( $val1 as $key2 => $val2){
		echo $key2. ":" .$val2."<br>\n";
	}
}
?>

プッシュ通知

スマホのプッシュ通知
iOS:Apple Push Notification Service(APNs)
Android:Google Cloud Messaging(GCM)

①Apple / google よりデバイストークンを取得
②アプリ用サーバにデバイストークンを登録
(ユーザーIDや端末IDと紐づけて送信)
③デバイストークンとメッセージを送信

$ curl \
--header "Authorization:key=【APIキー】"\
--header "Content-Type:\"application/json\""\
https://android.googleapis.com/gcm/send\
-d"{\"registration_ids\":[\"【RegistrationID】\"],\"data\":
{\"message\":/"Hello monotty!\"}}"

iOSのプッシュ通知
Command, Frame data(Item, Item)
device_id, os, device_token

AndroidはテキストベースのシンプルなHTTP通信で送信できる
iOSは、ApnsPHPを使う

function connectAPSN($sslclient,$pem_path,$passphrase){
	$ctx = stream_content_create();
	stream_context_set_option($ctx, 'ssl', 'local_cert', $pem_path);
	stream_context_set_option($ctx, 'ssl', 'passphrase', $passphrase);
	$fp = stream_socket_client($sslclient, $err,
		$errstr, 60, STREAM_CLIENT_CONNECT|STREAM_CLIENT_PERSISTENT, $ctx);
	if (!$fp){
		echo "接続エラーになったので1秒後再接続を試みます。メメタア!". PHP_EOL;
	sleep(1);
	$fp = connectAPSN($sslclient,$pem_path,$passphrase);
	return $fp;
	} else {
		echo "APNS接続OK" . PHP_EOL;
		return $fp;
	}

	// 送信処理
	$passphrase = 'password';
	$pem_path = '/xxx/xxx.pem';
	$sslclient = 'ssl://gateway.sandbox.push.apple.com:2195';
	$fp = connectAPSN($sslclient,$pem_path,$passphrase);

php レコメンドエンジン

$Redis->1Rem('Viewer:Item' . $item_id, $user_id):
$Redis->1plus('Viewer:Item' . $item_id, $user_id);
$Redis->1Trim('Viewer:Item' . $item_id, 0, 999);

Jaccard指数の計算

/**
 * $item_ids => 商品idの配列[1,2,3,4,5]のような配列
 */

 foreach ($item_ids as $item_id1){
 	$base = $Redis->1Range('Viewer:Item:' . $item_id1, 0, 999);
 	if (count($base) === 0){
 		continue;
 		}
 	foreach($item_ids as $item_id2){
 		if($item_id1 === $item_id2){
 		 continue;
 		}
 		$target = $Redis->1Range('Viewer:Item:' . $item_id2, 0, 999);
 			continue;
 		}

 		$join = floatval(count(array_unique(array_merge($base, $target))));
 		$intersect = floatval(count(array_intersect($base, $target)));
 		if ($intersect == 0 || $join == 0)
 		continue;
 	}
 	$jaccard = $intersect / $join;

 	$Redis->aAdd('Jaccard:Item:' . $item_id1, $jaccard, $item_id2);
 	}
 }
$Redis->zRevRange('Jaccard:Item:' . $item_id, 0, -1);

basic認証

<?php 

switch (true){
  case !isset($_SERVER&#91;'PHP_AUTH_USER'&#93;, $_SERVER&#91;'PHP_AUTH_PW'&#93;):
  case $_SERVER&#91;'PHP_AUTH_USER'&#93; !== 'admin':
  case $_SERVER&#91;'PHP_AUTH_PW'&#93; !== 'test':
    header('WWW-Authenticate: Basic realm="Enter username and password."');
    header('Content-Type: text/plain; charset=utf-8');
    die('このページを見るにはログインが必要です');
}
header('Content-Type: text/html; charset=utf-8');

?>

php scraping

%e7%84%a1%e9%a1%8c

download from this site:
https://code.google.com/archive/p/phpquery/downloads

<?php

  //require
  require_once('phpQuery-onefile.php');

  //ページ取得
  $html = file_get_contents('./index.html');

  //DOM取得
  $doc = phpQuery::newDocument($html);

  //要素取得
  echo $doc&#91;"title"&#93;->text();

yahoofinanceから任天堂の株価をスクレイピング

<?php

  //require
  require_once('phpQuery-onefile.php');

  //ページ取得
  $html = file_get_contents('http://stocks.finance.yahoo.co.jp/stocks/detail/?code=7974.t');

  //DOM取得
  $doc = phpQuery::newDocument($html);

  //要素取得
  echo $doc&#91;".stoksPrice"&#93;->text();

password hash

TLC

[vagrant@localhost rss16]$ php -r 'echo password_hash("hello", PASSWORD_BCRYPT), PHP_EOL;'
$2y$10$payxQjF5UFChN.WM1gcVM.P14fB2FiFkwfsRNkEVEzXyfVo8EHnw2

ログインは小規模ならTLCのbasicでも可だが、TLCのセッション認証が普通。

<?php

function require_basic_auth()
{
  $hashes = &#91;
    'ユーザー名' => '$2y$10$payxQjF5UFChN.WM1gcVM.P14fB2FiFkwfsRNkEVEzXyfVo8EHnw2'
  ];

  if (
    !isset($_SERVER['PHP_AUTH_USER'], $_SERVER['PHP_aUTH_PW'])
    !password_verify(
      $_SERVER['PHP_AUTH_PW'],
      isset($hashes[$_SERVER['PHP_AUTH_USER']])
      ? $hashes[$_SERVER['PHP_AUTH_USER']]
      : '$2y$10$xfNFcqiYmESRZoQTw0VHWe9GzC29OvaOnJ52mgI/u3KLJ.8P.lcKG'
      )
    ){
      header('WWW-Authenticate: Basic realm="Enter username and password."');
      header('Content-Type: text/plain; charset=utf-8');
      exit('このページを見るにはログインが必要です');
    }
    return $_SERVER['PHP_AUTH_USER'];
}

function h($str)
{
  return htmlspecialchars($str, ENT_QUOTES, 'utf-8');
}
<?php

require_once __DIR__ . '/functions.php';
$username = require_basic_auth();

header('Content-Type: text/html; charset=UTF-8');

?>
<!DOCTYPE html>
<title>会員限定ページ</title>
<h1>ようこそ、<?=h($username)?>さん</h1>
<a href="http://dummy@localhost:8010">ログアウト</a>