$config = parse_ini_file("config.ini");上記のコードでは、parse_ini_file() 関数を使用して、指定された config.ini ファイルからデータを読み込みます。読み込んだデータは、連想配列として $config 変数に格納されます。
[database] host = localhost username = root password = secret dbname = mydatabase [server] ip = 192.168.0.1 port = 8080上記の config.ini ファイルから、以下のような配列が生成されます。
Array ( [database] => Array ( [host] => localhost [username] => root [password] => secret [dbname] => mydatabase ) [server] => Array ( [ip] => 192.168.0.1 [port] => 8080 ) )上記のように、セクション名をキーとして、各キーに対応するセクション内のキーと値のペアが、2次元配列として格納されます。
$data = array(
'database' => array(
'host' => 'localhost',
'username' => 'root',
'password' => 'secret',
'dbname' => 'mydatabase'
),
'server' => array(
'ip' => '192.168.0.1',
'port' => '8080'
)
);
$config = '';
foreach ($data as $key => $value) {
$config .= "[$key]\n";
foreach ($value as $k => $v) {
$config .= "$k = $v\n";
}
$config .= "\n";
}
file_put_contents('config.ini', $config);
上記のコードでは、配列 $data をループ処理して、iniファイルの文字列を生成します。生成された文字列は file_put_contents() 関数を使用して、config.ini ファイルに書き込まれます。makefile Copy code [database] host = localhost username = root password = secret dbname = mydatabase [server] ip = 192.168.0.1 port = 8080上記のように、セクション名をキーとして、各キーに対応するセクション内のキーと値のペアが、iniファイルに書き込まれます。
sqlSanitize自作関数
function sqlSanitize($text) {
$text = trim($text);
// 文字列がUTF-8でない場合、UTF-8に変換する
if(!mb_check_encoding($text, 'UTF-8')){
$text = str_replace(['¥¥', '/', '¥'', '"', '`',' OR '], '', $text);
$text = mb_convert_encoding($text, 'UTF-8');
}
// SQLインジェクションのための特殊文字をエスケープする
$search = array("¥¥", "¥x00", "¥n", "¥r", "'", '"', "¥x1a", "`");
$replace = array("¥¥¥¥", "¥¥0", "¥¥n", "¥¥r", "¥¥'", "¥¥¥"", "¥¥Z", "");
$text = str_replace($search, $replace, $text);
return $text;
}
検証
// autoload.php
spl_autoload_register(function ($class) {
// プレフィックスまたは名前空間を置き換える(もし必要な場合)
$prefix = 'App\\';
$base_dir = __DIR__ . '/';
// クラスにプレフィックスがある場合
$len = strlen($prefix);
if (strncmp($prefix, $class, $len) !== 0) {
return;
}
// 名前空間やクラス名の残りの部分を取得
$relative_class = substr($class, $len);
// クラスファイルのパスを取得(ここで適切なディレクトリ構造に変更する)
$file = $base_dir . str_replace('\\', '/', $relative_class) . '.php';
// クラスファイルが存在する場合は読み込む
if (file_exists($file)) {
require $file;
}
});
このautoload.phpをプロジェクトのエントリポイント(通常はindex.php)で読み込むことで、必要なクラスが自動的に読み込まれるようになります。
// index.php
require 'path/to/autoload.php';
// 以下は自動で読み込まれる
$controller = new App\Controller\MyController();
$model = new App\Model\MyModel();
$view = new App\View\MyView();
上記のautoload.phpでは、クラスの名前空間がApp\で始まり、それに続く部分(Controller\MyController、Model\MyModelなど)がそのクラスが存在するディレクトリ構造と一致していることを前提としています。データベーステーブルの作成
まず、セッションデータを保存するためのデータベーステーブルを作成します。CREATE TABLE sessions ( id VARCHAR(128) NOT NULL PRIMARY KEY, data TEXT, timestamp TIMESTAMP NOT NULL );
カスタムセッションハンドラの作成
次に、カスタムセッションハンドラを作成します。この例では、PDO を使用しています。
class PDOSessionHandler
{
private $pdo;
public function __construct($pdo)
{
$this->pdo = $pdo;
}
public function open($savePath, $sessionName)
{
return true;
}
public function close()
{
return true;
}
public function read($id)
{
$stmt = $this->pdo->prepare("SELECT data FROM sessions WHERE id = :id");
$stmt->bindParam(':id', $id);
$stmt->execute();
if ($row = $stmt->fetch(PDO::FETCH_ASSOC)) {
return $row['data'];
}
return '';
}
public function write($id, $data)
{
$timestamp = time();
$stmt = $this->pdo->prepare("REPLACE INTO sessions (id, data, timestamp) VALUES (:id, :data, :timestamp)");
$stmt->bindParam(':id', $id);
$stmt->bindParam(':data', $data);
$stmt->bindParam(':timestamp', $timestamp, PDO::PARAM_INT);
return $stmt->execute();
}
public function destroy($id)
{
$stmt = $this->pdo->prepare("DELETE FROM sessions WHERE id = :id");
$stmt->bindParam(':id', $id);
return $stmt->execute();
}
public function gc($maxLifetime)
{
$old = time() - $maxLifetime;
$stmt = $this->pdo->prepare("DELETE FROM sessions WHERE timestamp < :old");
$stmt->bindParam(':old', $old, PDO::PARAM_INT);
return $stmt->execute();
}
}
使用方法
session_start()を実行する前に上記のクラスPDOSessionHandlerで設定処理を施します。
$pdo = new PDO("mysql:host=localhost;dbname=mydatabase", "username", "password");
$handler = new PDOSessionHandler($pdo);
session_set_save_handler(
[$handler, 'open'],
[$handler, 'close'],
[$handler, 'read'],
[$handler, 'write'],
[$handler, 'destroy'],
[$handler, 'gc']
);
// セッションを開始する
session_start();
これで、PDO を使用してセッションデータをデータベースに保存できるようになりました。$_SESSION変数を通常通り使用することで、そのデータは自動的にデータベースに保存されます。
この例は簡単なものであり、本番環境で使用する場合にはさまざまな点(エラーハンドリング、トランザクション処理、セキュリティなど)を考慮に入れる必要があります。
curl -v -X POST https://api.line.me/v2/bot/richmenu \
-H 'Authorization: Bearer lPdXJ1j4doZCNpA8xxxxxxxxxxxxxxxチャンネルアクセストークンxxxxxxxxxxxxijoqzvjjocigrg7oPCwCmUZXpXSXpXvi2GqIlV5QBSagUHTzrmKLSAdB04t89/1O/w1cDnyilFU=' \
-H 'Content-Type: application/json' \
-d \
'{
"size": {
"width": 2500,
"height": 843
},
"selected": false,
"name": "Animal Rich",
"chatBarText": "Tap to open",
"areas": [
{
"bounds": {
"x": 0,
"y": 0,
"width": 1250,
"height": 843
},
"action": {
"type": "uri",
"label": "Cat Tap",
"uri": "https://www.line-community.me/ja/"
}
},
{
"bounds": {
"x": 1250,
"y": 0,
"width": 1250,
"height": 843
},
"action": {
"type": "uri",
"label": "Dog Tap",
"uri": "https://techblog.lycorp.co.jp/ja/"
}
}
]
}'
{ [58 bytes data] 100 900 100 58 100 842 195 2844 --:--:-- --:--:-- --:--:-- 3050{"richMenuId":"richmenu-xxxリッチメニューIDxxxxb217e75d78d5fba09b254"} * Connection #0 to host api.line.me left intact
cd ~/git/tmp
$ curl -v -X POST https://api-data.line.me/v2/bot/richmenu/richmenu-xxxリッチメニューIDxxxxb217e75d78d5fba09b254/content \
-H "Authorization: Bearer lPdXJ1j4doZCNpA8xxxxxxxxxxxxxxxチャンネルアクセストークンxxxxxxxxxxxxijoqzvjjocigrg7oPCwCmUZXpXSXpXvi2GqIlV5QBSagUHTzrmKLSAdB04t89/1O/w1cDnyilFU=" \
-H "Content-Type: image/png" \
-T rich_menu_green_2.png
特に、エラーがでなければ成功です。
$ curl -v -X POST https://api.line.me/v2/bot/user/all/richmenu/richmenu-xxxリッチメニューIDxxxxb217e75d78d5fba09b254 \
-H "Authorization: Bearer lPdXJ1j4doZCNpA8xxxxxxxxxxxxxxxチャンネルアクセストークンxxxxxxxxxxxxijoqzvjjocigrg7oPCwCmUZXpXSXpXvi2GqIlV5QBSagUHTzrmKLSAdB04t89/1O/w1cDnyilFU="
RichMenuCurl.php
<?php
class RichMenuCurl{
/**
* LINEリッチメニューのテンプレートをLINEに送信し、LINEリッチメニューIDを取得する
*
* @param array $param
*/
public function curlTemplateToLine($param = []){
$access_token = $param['access_token'];
// LINE APIのURL
$url = 'https://api.line.me/v2/bot/richmenu';
// リクエストヘッダー
$headers = [
"Authorization: Bearer {$access_token}",
'Content-Type: application/json',
];
// 送信するデータ
$data = json_encode([
"size" => [
"width" => 2500,
"height" => 843
],
"selected" => false,
"name" => "Animal Rich",
"chatBarText" => "Tap to open",
"areas" => [
[
"bounds" => [
"x" => 0,
"y" => 0,
"width" => 1250,
"height" => 843
],
"action" => [
"type" => "uri",
"label" => "my_home",
"uri" => "https://amaraimusi.sakura.ne.jp/"
]
],
[
"bounds" => [
"x" => 1250,
"y" => 0,
"width" => 1250,
"height" => 843
],
"action" => [
"type" => "uri",
"label" => "Jisin",
"uri" => "https://www.jma.go.jp/bosai/map.html#5/32.12/137.856/&contents=hypo"
]
]
]
]);
// cURLセッションの初期化
$ch = curl_init($url);
// オプションの設定
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// リクエストの実行
$response = curl_exec($ch);
// エラーチェック
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
}
// cURLセッションの終了
curl_close($ch);
// レスポンスの表示
$res=json_decode($response,true);//JSON文字を配列に戻す
$richMenuId = $res['richMenuId'];
return $richMenuId;
}
/**
* LINEリッチメニューの画像をLINEに送信する
*
* @param array $param
*/
public function curlImgToLine($params){
$access_token = $params['access_token'];
$line_rich_menu_id = $params['line_rich_menu_id'];
$img_path = $params['img_path'];
// ファイルの拡張子を取得し、拡張子を小文字に変換
$ext = pathinfo($img_path, PATHINFO_EXTENSION);
$ext = strtolower($ext);
// MIMEタイプの確認(サポートされている形式のみ)
if ($ext != "jpg" && $ext != "jpeg" && $ext != "png") {
echo "Unsupported file format";
return;
}
// 正しいMIMEタイプを設定
$mime = ($ext == "png") ? "image/png" : "image/jpeg";
// LINE APIのエンドポイント
$url = "https://api-data.line.me/v2/bot/richmenu/{$line_rich_menu_id}/content";
// ヘッダー
$headers = [
"Authorization: Bearer {$access_token}",
"Content-Type: {$mime}"
];
// cURLセッションの初期化
$ch = curl_init($url);
// ファイルの内容を読み込む
$data = file_get_contents($img_path);
if ($data === false) {
echo "Failed to read file";
return;
}
// オプションの設定
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// リクエストの実行
$response = curl_exec($ch);
// エラーチェック
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
}
// cURLセッションの終了
curl_close($ch);
return $response;
}
/**
* LINEリッチメニューをデフォルトに設定するようLINEに送信する(リッチメニューを適用)
*
* @param array $param
*/
public function curlDefaultToLine($params){
$access_token = $params['access_token'];
$line_rich_menu_id = $params['line_rich_menu_id'];
// LINE APIのエンドポイント
$url = "https://api.line.me/v2/bot/user/all/richmenu/{$line_rich_menu_id}";
// ヘッダー
$headers = [
"Authorization: Bearer {$access_token}"
];
// cURLセッションの初期化
$ch = curl_init($url);
// オプションの設定
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'POST');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
// リクエストの実行
$response = curl_exec($ch);
// エラーチェック
if (curl_errno($ch)) {
echo 'Error:' . curl_error($ch);
}
// cURLセッションの終了
curl_close($ch);
// レスポンスの表示
return $response;
}
/**
* LINEプラットフォームに登録されているリッチメニュー一覧の情報を取得する
*
* @param array $param
*/
public function curlListFromLine($params){
$access_token = $params['access_token'];
// 初期化
$curl = curl_init();
// cURLオプションの設定
curl_setopt($curl, CURLOPT_URL, "https://api.line.me/v2/bot/richmenu/list");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
"Authorization: Bearer {$access_token}"
));
// HTTPリクエストの実行
$response = curl_exec($curl);
// エラーチェック
if(curl_errno($curl)){
echo 'Curl error: ' . curl_error($curl);
}
// cURLセッションの終了
curl_close($curl);
$res = json_decode($response, true);
return $res;
}
/**
* LINEリッチメニューを削除するようLINEに送信する(リッチメニューIDを指定して削除)
*
* @param array $param
*/
public function curlDeleteToLine($params){
$access_token = $params['access_token'];
$line_rich_menu_id = $params['line_rich_menu_id'];
// cURLセッションを初期化
$curl = curl_init();
// cURLオプションの設定
curl_setopt($curl, CURLOPT_URL, "https://api.line.me/v2/bot/richmenu/{$line_rich_menu_id}");
curl_setopt($curl, CURLOPT_CUSTOMREQUEST, "DELETE");
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_HTTPHEADER, array(
"Authorization: Bearer {$access_token}"
));
// HTTPリクエストを実行
$response = curl_exec($curl);
// エラーチェック
if (curl_errno($curl)) {
echo 'Curl error: ' . curl_error($curl);
}
// cURLセッションを閉じる
curl_close($curl);
$res = json_decode($response, true);
return $res;
}
}
クライアント
<?php
// 通信元から送信されてきたパラメータを取得する。
$params_json = $_POST['key1'];
$params=json_decode($params_json,true);//JSON文字を配列に戻す
$mode = $params['mode'];
require_once 'RichMenuCurl.php';
$richMenuCurl = new RichMenuCurl();
switch ($mode) {
case 'template_to_line':
$line_rich_menu_id = $richMenuCurl->curlTemplateToLine($params);
$params['line_rich_menu_id'] = $line_rich_menu_id;
break;
case 'img_to_line':
$params['img_path'] = __DIR__ . '/img/' . $params['rich_menu_img'];
$params['res'] = $richMenuCurl->curlImgToLine($params);
break;
case 'default_to_line':
$params['res'] = $richMenuCurl->curlDefaultToLine($params);
break;
case 'list_from_line':
$params['res'] = $richMenuCurl->curlListFromLine($params);
break;
case 'delete_to_line':
$params['res'] = $richMenuCurl->curlDeleteToLine($params);
break;
}
// JSONに変換し、通信元に返す。
$json_str = json_encode($params, JSON_HEX_TAG | JSON_HEX_QUOT | JSON_HEX_AMP | JSON_HEX_APOS);
echo $json_str;
/**
* 指定したディレクトリを再帰的に削除するメソッド
*
* @param string $dir 削除対象のディレクトリのパス
* @throws InvalidArgumentException
*/
public function rmdirEx($dir)
{
if (!is_dir($dir)) {
return;
}
$this->deleteDirectoryContents($dir);
// 最後にディレクトリ自体を削除
rmdir($dir);
}
/**
* ディレクトリの中身を再帰的に削除する
*
* @param string $dir
*/
private function deleteDirectoryContents($dir)
{
$items = scandir($dir);
foreach ($items as $item) {
if ($item === '.' || $item === '..') {
continue;
}
$path = $dir . DIRECTORY_SEPARATOR . $item;
if (is_dir($path)) {
// サブディレクトリの場合、再帰的に削除
$this->rmdirEx($path);
} else {
// パーミッションを変更してファイルを削除
if (!is_writable($path)) {
chmod($path, 0666);
}
unlink($path);
}
}
}
/**
* 再帰的にディレクトリをコピーするメソッド
*
* @param string $sourceDir コピー元のディレクトリパス
* @param string $destDir コピー先のディレクトリパス
* @return bool コピーが成功した場合は true、失敗した場合は false
*/
public function copyDirEx(string $sourceDir, string $destDir): bool
{
// コピー元のディレクトリが存在しない場合、falseを返す
if (!is_dir($sourceDir)) {
return false;
}
// コピー先のディレクトリが存在しない場合、作成する
if (!is_dir($destDir)) {
mkdir($destDir, 0755, true);
}
// ディレクトリハンドルを開く
$dirHandle = opendir($sourceDir);
if ($dirHandle === false) {
return false;
}
// ディレクトリ内のファイルやフォルダをループ
while (($file = readdir($dirHandle)) !== false) {
if ($file === '.' || $file === '..') {
continue;
}
$sourcePath = $sourceDir . DIRECTORY_SEPARATOR . $file;
$destPath = $destDir . DIRECTORY_SEPARATOR . $file;
if (is_dir($sourcePath)) {
// 再帰的にディレクトリをコピー
if (!$this->copyDirEx($sourcePath, $destPath)) {
closedir($dirHandle);
return false;
}
} else {
// ファイルをコピー
if (!copy($sourcePath, $destPath)) {
closedir($dirHandle);
return false;
}
}
}
// ディレクトリハンドルを閉じる
closedir($dirHandle);
return true;
}