- 投稿日:2020-08-20T22:10:38+09:00
生年月日から年齢を計算して表示させる JavaScript PHP
少し前の案件で「会社概要ページの代表者プロフィールに年齢を表記する」ってことがあって、
年齢は毎年変わるから自動で更新させないとなー、と思いつつ面倒くさくてそのまま表記したって事がありました。その事を思い出して、jsとphpで年齢を計算して表示させるってのを作ってみました。
jsかphpのどちらかで実装できるので、好きな方を使ってください。PHPで年齢を計算して表示
"19910402"の部分が生年月日です、年齢を表示させたい人の生年月日に変更してください。
ちなみに1991年4月2日は僕の誕生日です。php年齢は<?php echo floor((date('Ymd') - 19910402) / 10000); ?>歳です。実行結果年齢は29歳です。JavaScriptで年齢を計算して表示
同じく"19910402"の部分が生年月日です、年齢を表示させたい人の生年月日に変更してください。
html年齢は<span id="age"></span>歳です。javascriptfunction calcAge(birthdate) { const today = new Date(); targetdate = today.getFullYear() * 10000 + (today.getMonth() + 1) * 100 + today.getDate(); return (Math.floor((targetdate - birthdate) / 10000)); } document.getElementById("age").innerHTML = calcAge(19910402);実行結果年齢は29歳です。まとめ
現在の日付から生年月日を引いて、1万で割ると年齢が出るらしいです。
数学って不思議。
- 投稿日:2020-08-20T22:04:24+09:00
ラズパイとカメラを使用してカラーセンサー作成
要望 加工品のつまり、終了を見抜きたい
機械工作工場にて自動レーンでの製品のつまり、最終加工品の完了した時を知りたい。
バルブの赤いハンドルの位置(開閉表示)を知りたい。
製品は黄色、背景(レーン)は白、青、又は黒の原色。
既製品のセンサーが高すぎるので安く作って欲しいとの要望。完成品
ラズパイをローカルWIFIにつなげて。
http://"ラズパイのIPアドレス"/home.phpカメラ画像から当該箇所を指定して抜き出す。
色範囲を指定して、色範囲に入った場合GPIOを出力する。
GPIOの出力にて警報ランプを起動させる。
警報解除は警報リセットにて行う。ラズパイ環境設定
python OpenCV ダウンロード
参考サイト 計算機科学を学んだソフトウェア技術者の経験やメモなどの記録様
sudo apt-get install libopencv-dev
sudo apt-get install python-opencvアパッチダウンロード
参考サイト @mono_taro様
sudo apt-get update
sudo apt-get upgrade
sudo apt-get install apache2
apachectl -vphpダウンロード
参考サイト The modern stone age.様
sudo apt install php7.2 libapache2-mod-php7.2php及びhtml作成
/var/www/html/home.php<html> <head> <meta http-equiv="content-type" charset="utf-8"> <meta http-equiv="Cache-Control" content="no-cache"> <meta http-equiv="refresh" content="5" > </head> </html> <form action="set.php" method="get"> <body> <h1>カメラ画像</h1> <?php $lines_reset = file('/home/pi/Documents/reset.csv'); foreach($lines_reset as $line_reset){ $data_reset = explode(',',$line_reset); if ($data_reset[0] == 1){ echo "<FONT COLOR=\"RED\"> 現在警報動作中 解除する場合は下ボタンにて </FONT>";} } ?> <img src="1.jpg?1"> <h2>抜出画像</h2> <img src="2.jpg?1"> </body> <?php $lines = file('/home/pi/Documents/color.csv'); foreach($lines as $line){ $data = explode(',',$line); echo '<p>'; echo ' 赤色R',$data[0]; echo ' 緑色G:',$data[1]; echo ' 青色B:',$data[2]; echo '</p>'; } ?> <a href="./set.html">設定画面</a> <a href="./reset.html">警報リセット</a> </form>/var/www/html/set.html<form action="set.php" method="get"> <p> <a href="./home.php">戻る</a> </p> <img src="1.jpg"> <p>色の範囲指定</p> <p>赤下限: <input type="number" name="r_2_1" value="1" min="0" max="255"></p> <p>赤上限: <input type="number" name="r_2_2" value="1" min="0" max="255"></p> <p>緑下限: <input type="number" name="g_2_1" value="1" min="0" max="255"></p> <p>緑上限: <input type="number" name="g_2_2" value="1" min="0" max="255"></p> <p>青下限: <input type="number" name="b_2_1" value="1" min="0" max="255"></p> <p>青上限: <input type="number" name="b_2_2" value="1" min="0" max="255"></p> <p>画像抜出ファイル 上下は上からの距離、左右は左からの距離</p> <p>上top: <input type="number" name="top" value="1" min="0" max="2000"></p> <p>下bot: <input type="number" name="bot" value="100" min="0" max="2000"></p> <p>左left: <input type="number" name="left" value="1" min="0" max="2000"></p> <p>右right: <input type="number" name="right" value="100" min="0" max="2000"></p> <p>シャッター間隔、規定回数</p> <p>シャッター間隔 秒(s): <input type="number" name="interval" value="60" min="10" max="6000"></p> <p>回数: <input type="number" name="nutime" value="1" min="1" max="100"></p> <input type="submit" /> <p> </p> <p>補足色説明</p> <p>赤色 R255 G0 B0</p> <p>黒 R0 G0 B0</p> <p>白 R255 G255 B255</p> <p>黄色 R255 G255 B0</p> <p>灰色 R128 G128 B128</p> <p>その他の色はRGB色で検索願います。</p> <p>規定回数とは連続で指定範囲内に入った回数の時、リレーが作動する回数</p> </form>/var/www/html/set.php<meta http-equiv="content-type" charset="utf-8"> <?php $r_2_1=htmlspecialchars($_GET["r_2_1"],ENT_QUOTES); $r_2_2=htmlspecialchars($_GET["r_2_2"],ENT_QUOTES); $g_2_1=htmlspecialchars($_GET["g_2_1"],ENT_QUOTES); $g_2_2=htmlspecialchars($_GET["g_2_2"],ENT_QUOTES); $b_2_1=htmlspecialchars($_GET["b_2_1"],ENT_QUOTES); $b_2_2=htmlspecialchars($_GET["b_2_2"],ENT_QUOTES); $top=htmlspecialchars($_GET["top"],ENT_QUOTES); $bot=htmlspecialchars($_GET["bot"],ENT_QUOTES); $left=htmlspecialchars($_GET["left"],ENT_QUOTES); $right=htmlspecialchars($_GET["right"],ENT_QUOTES); $interval=htmlspecialchars($_GET["interval"],ENT_QUOTES); $nutime=htmlspecialchars($_GET["nutime"],ENT_QUOTES); ?> <body> <?php echo $_GET["r_2_1"]; ?> <?php $data = [ [$_GET["r_2_1"], $_GET["r_2_2"], $_GET["g_2_1"], $_GET["g_2_2"], $_GET["b_2_1"], $_GET["b_2_2"], $_GET["top"], $_GET["bot"], $_GET["left"], $_GET["right"], $_GET["interval"], $_GET["nutime"]], ]; $fp = fopen('/home/pi/Documents/position.csv', 'w'); foreach ($data as $line) { fputcsv($fp, $line); } fclose($fp); ?> <p> <a href="./home.php">戻る</a> </p>/var/www/html/reset.html<meta http-equiv="content-type" charset="utf-8"> <meta http-equiv="Cache-Control" content="no-cache"> <form action="reset.php" method="get"> <input type="submit" /> </form>/var/www/html/reset.php<meta http-equiv="content-type" charset="utf-8"> <?php $data = [["0"]]; $fp = fopen('/home/pi/Documents/reset.csv', 'w'); foreach ($data as $line) { fputcsv($fp, $line);} fclose($fp); ?> <p> <a href="./home.php">戻る</a> </p>python 及びCSV作成
/home/pi/Documents/gazou.py#!/usr/bin/python # -*- coding: utf-8 -*- import cv2, os import numpy as np import csv import time import RPi.GPIO as GPIO time.sleep(60)#ラズパイ起動時の待機時間 #GPIO設定 PIN = 14 GPIO.setmode(GPIO.BCM) GPIO.setup(PIN, GPIO.OUT) #イメージファイルの保存場所 image_file = '/var/www/html/1.jpg' #写真撮影 image_file_2 = '/var/www/html/2.jpg' #検証1 #読み込み用CSVの場所 poss = '/home/pi/Documents/position.csv' colo_0 = '/home/pi/Documents/color0.csv' colo_1 = '/home/pi/Documents/color.csv' poss_reset = '/home/pi/Documents/reset.csv' while True: try : with open(poss) as data0:#切り出し場所を読み取る reader = csv.reader(data0) data1 = [row for row in reader] #範囲読み取り r_2_1 = int(data1[0][0]) #赤下限 img2 r_2_2 = int(data1[0][1]) #赤上限 img2 g_2_1 = int(data1[0][2]) #緑下限 img2 g_2_2 = int(data1[0][3]) #緑上限 img2 b_2_1 = int(data1[0][4]) #青下限 img2 b_2_2 = int(data1[0][5]) #青上限 img2 #img2.jpgの切り出し部分 top_2 = int(data1[0][6]) bot_2 = int(data1[0][7]) left_2 = int(data1[0][8]) right_2 = int(data1[0][9]) #繰り返し秒数及び動作確認数 jobs_s = int(data1[0][10]) time.sleep(jobs_s) with open(poss_reset) as data_reset:#リセットCSV読み取り reader_reset = csv.reader(data_reset) data_reset1 = [row for row in reader_reset] data_resset2 = int(data_reset1[0][0]) with open(colo_0) as data2:#書き込み用のデフォルトデータを読み込む reader = csv.reader(data2) data3 = [row for row in reader] cam = cv2.VideoCapture(0) # カメラから映像を読み込む _, img = cam.read() # 画像ファイルとして書き出す img2 = img[top_2 : bot_2, left_2: right_2] #イメージ保存 cv2.imwrite(image_file, img) cv2.imwrite(image_file_2, img2) # RGB平均値を出力 # flattenで一次元化しmeanで平均を取得 r2 = img2.T[2].flatten().mean() g2 = img2.T[1].flatten().mean() b2 = img2.T[0].flatten().mean() if data_resset2 == 0: GPIO.output(PIN, GPIO.LOW) #とりあえず切る if r_2_1 < r2 < r_2_2 and g_2_1 < g2 < g_2_2 and b_2_1 < b2 < b_2_2: GPIO.output(PIN, GPIO.HIGH) data_resset2 = 1 # RGB平均値を取得 data3[0][0] = '%.0f' % r2 data3[0][1] = '%.0f' % g2 data3[0][2] = '%.0f' % b2 #CSVを保存 with open(colo_1, 'w') as f: writer = csv.writer(f) for data4 in data3: writer.writerow(data4) data_reset1[0][0] = data_resset2 with open(poss_reset, 'w') as f: writer = csv.writer(f) for data_reset2 in data_reset1: writer.writerow(data_reset2) # 事後処理 cam.release() cv2.destroyAllWindows() except: time.sleep(30) pass/home/pi/Documents/position.csv1,1,1,1,1,1,1,100,1,100,60,1/home/pi/Documents/color0.csv100,100,100,100,100,100/home/pi/Documents/color.csv100,100,100,100,100,100/home/pi/Documents/reset.csv0起動時にpythonを起動する設定をする。
sudo にて gazou.pyを自動起動する。
sudo でないと/var/www/html/にjpgの画像を書き込まない
参考サイト@yuru-camper様使用したカメラ
C270N HD WEBCAM
logicool様サイト将来やりたい事
設定画面が下記のように設定しにくいので抜き出し箇所はマウスで選択できるようにしたい。
色設定もマウスで決定できるようにしたい。
現在の状態だと設定がトライアンドエラーをたくさん繰り返さなくてはいけない。
- 投稿日:2020-08-20T21:55:00+09:00
DockerでGD Libraryのエラー対応
LaravelをローカルのDockerで動かしていて、
画像の圧縮しようとしたときにつまずいたのでメモ。エラー
GD Library extension not available with this PHP installation.PHPのGDライブラリが使用できないらしい。
早速Dockerfileを編集結論だけ言うと、このようなDockerfileになりました
FROM php:7.4-fpm COPY php.ini /usr/local/etc/php/ RUN apt-get update \ && apt-get install -y wget git unzip libzip-dev libpq-dev libfreetype6-dev libjpeg62-turbo-dev libpng-dev \ && docker-php-ext-install zip pdo_mysql \ && docker-php-ext-configure gd --with-freetype --with-jpeg \ && docker-php-ext-install -j$(nproc) gd #Composer install COPY --from=composer /usr/bin/composer /usr/bin/composer ENV COMPOSER_ALLOW_SUPERUSER 1 ENV COMPOSER_HOME /composer ENV PATH $PATH:/composer/vendor/bin WORKDIR /var/www RUN composer global require "laravel/installer"Dockerfileの変更を反映
イメージ:再構築の必要あり:docker-compose build
コンテナ:再構築の必要あり:docker-compose up -d無事にエラーが出なくなりました。
- 投稿日:2020-08-20T18:57:57+09:00
[PHP]特定のYouTube動画の情報を取得する
特定チャンネルの動画情報だったりプレイリスト一覧を取得したいとき、YouTubeAPIv3を使うと思います。
PHPだと、ComposerとかでGoogle公式ライブラリを使うのもいいですが特定の動画の場合はもっとかんたんに動画情報を取得できます。具体的にはAPIから動画情報が格納されているJSONを呼び出します。
以上!JSONのURL構造
[APIKey]にはGoogleAPIから取得したAPIキーを入力してください。
キーの取得方法はネットに溢れかえってるんで自分で調べてください。サンプルコード
YouTubeAPIv3から特定動画のタイトルを取得してみます。
yt.php$api_key = APIキーを入力 $video_id = 動画IDを入力 $url = "https://www.googleapis.com/youtube/v3/videos?id=$video_id&key=$api_key&part=snippet,contentDetails,statistics,status"; $json = file_get_contents($url); $getData = json_decode( $json , true); foreach((array)$getData['items'] as $key => $gDat){ $title = $gDat['snippet']['title']; } // タイトルをechoする echo $title;
- 投稿日:2020-08-20T18:20:58+09:00
PHPでOpenCVを使うまで(OpenCV-for-PHP)
PHPでOpenCVを利用する方法はいくつかあるようですが
OpenCV-for-PHPを利用する方法を紹介します。[mgdm/OpenCV-forPHP]
https://github.com/mgdm/OpenCV-for-PHP注意:
OpenCV-for-PHPはOpenCVの全ての関数がラップされていないので
利用したいOpenCVの関数が準備されていない場合、ご自身でOpenCV-for-PHP
ソースコードの改修・ビルドが必要になります。インストール前準備
インストールに必要なミドルウェアとバージョン
OpenCV 2.4.13
PHP5.2動作確認できたOS
CentOS5
CentOS7OpenCV2.4 インストール
OpenCVのビルドにgccとcmakeが必要なためそれぞれインストールします。
cmakeは、ソースコードcmake-2.8.12.1.tar.gzをダウンロードしてきて
ビルドしました。rpmパッケージがあればそちらを利用しても大丈夫と思います。gccインストール
yum install gcc44 gcc44-c++cmakeインストール
cd /usr/local/src tar xzvf cmake-2.8.12.1.tar.gz cd cmake-2.8.12.1 .configure make make installopencvインストール
OpenCV2.1以降が要求されますが、2.4以降に実装されている機能を利用したいため
OpenCV2.4.13をダウンロードしました。
こちらもrpmパッケージを利用しても大丈夫かと思います。https://sourceforge.net/projects/opencvlibrary/files/opencv-unix/2.4.13/opencv-2.4.13.zip/download
ビルドの際の注意点としてビルド用のディレクトリ(名前は何でもOK、手順ではbuildディレクトリ)を作成する必要があります。
cd /usr/local/src unzip opencv-2.4.13.zip cd opencv-2.4.13 mkdir build cd build cmake -D BUILD_EXAMPLES=YES -D CMAKE_BUILD_TYPE=RELEASE -D CMAKE_INSTALL_PREFIX=/usr/local/opencv -D BUILD_NEW_PYTHON_SUPPORT=NO -D WITH_1394=OFF -D CMAKE_C_COMPILER=gcc44 -D CMAKE_CXX_COMPILER=g++44 ../ make make installライブラリ及びパッケージ登録
cd /etc/ld.so.conf.d vi opencv.confopencv.conf/usr/local/opencv/libldconfig cd /usr/lib/pkgconfig ln -s /usr/local/opencv/lib/pkgconfig/opencv.pc .PHP5.4インストール
OpenCV-for-PHPのビルド時に
PHP5.2以降を要求されますが、こちらの環境の都合上5.4をインストール
しました。CentOS5の場合の手順になりますが、CentOS7の場合もyumレポジトリの追加以外は
ほぼ同様になります。インストール済みのPHPを削除
#yum remove php php-*PHP5.4のインストール
(利用するパッケージは環境に応じて選択してください。)rpm -ivh http://rpms.remirepo.net/enterprise/remi-release-5.rpm yum --enablerepo=epel install libedit yum --enablerepo=epel install t1lib yum install --enablerepo=remi php php-pdo php-cli php-bcmath php-mbstring php-devel php-common php-mysql php-ldap php-gd yum install --enablerepo=remi php-mcrypt php-pearphp.ini設定
date.timezone、mbstringの文字コード等設定を行います。OpenCV-for-PHPのインストール
gitインストール
yum install --enablerepo=epel gitOpenCV-for-PHPのビルド
cd /usr/local/src git clone git://github.com/mgdm/OpenCV-for-PHP.git cd OpenCV-for-PHP phpize .configure make installvi /etc/php.d/opencv.iniopencv.iniextension=opencv.sophp -mでopencvが存在することを確認します。
php -m [PHP Modules] ..略.. opencv ..略..以上になります。
使い方は、OpenCV-for-PHP(https://github.com/mgdm/OpenCV-for-PHP)
内のexampleが参考になります。全てのOpenCV関数が揃ってるわけではないため
OpenCVのリファレンスを参照して
https://docs.opencv.org/2.4/modules/refman.htmlOpenCV-for-PHPのソースコード改修を行います。
- 投稿日:2020-08-20T16:17:29+09:00
【PHPでECサイト④】購入履歴・購入明細
はじめに
今回は、購入履歴を実装していきます。
※当ページは、【PHPでECサイト】で作られたものを前提にしています。バージョン
PHP:7.4.5
phpMyAdmin:5.0.2
MySQL:5.7.30今回作成するファイル
html
- history.php
- detail.phpmodel
- histories.phpview
- history_view.php
- detail_view.phpテーブルの作成
sample_historiesCREATE TABLE `sample_histories` ( `order_id` int(11) NOT NULL, `user_id` int(11) NOT NULL, `created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ALTER TABLE `sample_histories` MODIFY `order_id` int(11) NOT NULL AUTO_INCREMENT, ADD PRIMARY KEY (`order_id`), ADD KEY `user_id` (`user_id`);sample_detailsCREATE TABLE `sample_details` ( `order_id` int(11) NOT NULL, `item_id` int(11) NOT NULL, `amount` int(11) NOT NULL, `created` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP ) ENGINE=InnoDB DEFAULT CHARSET=utf8; ALTER TABLE `sample_details` ADD KEY `item_id` (`item_id`);定義
const.phpdefine('HISTORY_URL', '/order_history.php'); define('DETAIL_URL', 'order_detail.php');カートの購入処理に追記
carts.php// 購入処理 function purchase_carts($db, $carts){ if(validate_cart_purchase($carts) === false){ return false; } // 購入後、カートの中身削除&在庫変動&購入履歴・明細にデータを挿入 $db->beginTransaction(); try { insert_history($db, $carts[0]['user_id']); $order_id = $db->lastInsertId(); foreach($carts as $cart){ insert_detail($db, $order_id, $cart['item_id'], $cart['price'], $cart['amount']); if(update_stock($db, $cart['item_id'], $cart['stock'] - $cart['amount']) === false){ set_error($cart['name'] . 'の購入に失敗しました。'); } } delete_user_carts($db, $carts[0]['user_id']); $db->commit(); }catch(PDOException $e){ $db->rollback(); throw $e; } } // 購入履歴へINSERT function insert_history($db, $user_id){ $sql = " INSERT INTO sample_histories( user_id ) VALUES(?) "; return execute_query($db, $sql, array($user_id)); } // 購入明細にINSERT function insert_detail($db, $order_id, $item_id, $price, $amount){ $sql = " INSERT INTO sample_details( order_id, item_id, price, amount ) VALUES(?,?,?,?) "; return execute_query($db, $sql, array($order_id, $item_id, $price, $amount)); }購入履歴
Model
histories.php<?php require_once MODEL_PATH. 'functions.php'; require_once MODEL_PATH. 'db.php'; // ユーザ毎の購入履歴 function get_history($db, $user_id){ $sql = " SELECT sample_histories.order_id, sample_histories.created, SUM(sample_details.price * sample_details.amount) AS total FROM sample_histories JOIN sample_details ON sample_histories.order_id = sample_details.order_id WHERE user_id = ? GROUP BY order_id ORDER BY created desc "; return fetch_all_query($db, $sql, array($user_id)); }View
history_view.php<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>購入履歴</title> </head> <body> <h1>購入履歴</h1> <!-- メッセージ・エラーメッセージ --> <?php include VIEW_PATH. 'templates/messages.php'; ?> <!-- 購入履歴 --> <?php if(!empty($histories)){ ?> <table> <thead> <tr> <th>注文番号</th> <th>購入日時</th> <th>合計金額</th> <th></th> </tr> </thead> <tbody> <?php foreach($histories as $history){ ?> <tr> <td><?php print($history['order_id']); ?></td> <td><?php print($history['created']); ?></td> <td><?php print($history['total']); ?></td> <td> <form method="post" action="detail.php"> <input type="submit" value="購入明細表示"> <input type="hidden" name="order_id" value="<?php print($history['order_id']); ?>"> </form> </td> </tr> <?php } ?> </tbody> </table> <?php }else{ ?> <p>購入履歴がありません。</p> <?php } ?> </body> </html>Controller
history.php<?php require_once '../conf/const.php'; require_once MODEL_PATH. 'functions.php'; require_once MODEL_PATH. 'users.php'; require_once MODEL_PATH. 'items.php'; require_once MODEL_PATH. 'carts.php'; require_once MODEL_PATH. 'histories.php'; session_start(); if(is_logined() === false){ redirect_to(LOGIN_URL); } $db = get_db_connect(); $user = get_login_user($db); $histories = get_history($db, $user['user_id']); $order_id = get_post('order_id'); include_once VIEW_PATH. 'history_view.php';購入明細
Model
histories.php// ユーザ毎の購入明細 function get_detail($db, $order_id){ $sql = " SELECT sample_details.price, sample_details.amount, sample_details.created, SUM(sample_details.price * sample_details.amount) AS subtotal, sample_items.name FROM sample_details JOIN sample_items ON sample_details.item_id = sample_items.item_id WHERE order_id = ? GROUP BY sample_details.price, sample_details.amount, sample_details.created, sample_items.name "; return fetch_all_query($db, $sql, array($order_id)); }View
detail_view.php<!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>購入明細</title> </head> <body> <h1>購入明細</h1> <!-- メッセージ・エラーメッセージ --> <?php include VIEW_PATH. 'templates/messages.php'; ?> <!-- 購入明細 --> <table> <thead> <tr> <th>注文番号</th> <th>購入日時</th> <th>合計金額</th> </tr> </thead> <tbody> <?php foreach($histories as $history){ ?> <tr> <td><?php print($history['order_id']); ?></td> <td><?php print($history['created']); ?></td> <td><?php print($history['total']); ?></td> <td> <form method="post" action="detail.php"> <input type="submit" value="購入明細表示"> <input type="hidden" name="order_id" value="<?php print($history['order_id']); ?>"> </form> </td> </tr> <?php } ?> </tbody> </table> <!-- 購入明細 --> <table> <thead> <tr> <th>商品名</th> <th>価格</th> <th>購入数</th> <th>小計</th> </tr> </thead> <tbody> <?php foreach($details as $detail){ ?> <tr> <td><?php print($detail['name']); ?></td> <td><?php print($detail['price']); ?></td> <td><?php print($detail['amount']); ?></td> <td><?php print($detail['subtotal']); ?></td> </tr> <?php } ?> </tbody> </table> </body> </html>Controller
detail.php<?php require_once '../conf/const.php'; require_once MODEL_PATH. 'functions.php'; require_once MODEL_PATH. 'users.php'; require_once MODEL_PATH. 'items.php'; require_once MODEL_PATH. 'carts.php'; require_once MODEL_PATH. 'histories.php'; session_start(); if(is_logined() === false){ redirect_to(LOGIN_URL); } $db = get_db_connect(); $user = get_login_user($db); $histories = get_history($db, $user['user_id']); $order_id = get_post('order_id'); $details = get_detail($db, $order_id); include_once VIEW_PATH. 'detail_view.php';
- 投稿日:2020-08-20T15:16:05+09:00
Laravelのpaginationで取得したcollectionデータの更新方法
Laravelのpaginationで取得したデータは特殊なcollectionクラスであるため、
新しいcollectionクラスを返すfilterやmapのような操作では要素が更新できません。$articles->getCollection()->transform( function ($article, $key) { //操作 return $article; } );のようにgetCollectionを使ってからtransformで変形することが必要です。
ここで、注意しなくてはいけないのは、articleの下にさらにcollectionがネストしている場合[1]も、
新しいcollectionクラスを返す操作ではそのcollectionクラスが更新できないという点です。その場合はgetCollectionなしのtransformで更新できますが、
要素を削除する場合はunset等の新しいcollectionを返さないで削除できる手段を用いる必要があります。
ただこれネストしているのでもっといい方法あるかもしれないけど//articleの下にhashtagがネストしている $articles->getCollection()->transform( function ($article, $key) { $article["tags"]->transform(function($tag,$key){ //タグ更新の場合。ちなみにここで何もreturnしなかった場合、nullが代入される。 return $tag; } //要素削除の場合 foreach($article["tags"] as $key=>$tag){ //条件を入れる。ここは例えばタグの名前がtestの場合 if(($tag["name"]==='test')){ //条件に合致したものをunset unset($article["hashtags"][$key]); } } return $article; } );[1]元データがModelでwith等を使ってクエリを作っている場合等。
- 投稿日:2020-08-20T14:37:27+09:00
Herokuを使って開発アプリを本番環境へデプロイする
開発環境
- PHP 7.2
- Laravel 5.6
- MySQL 5.7
- Docker
- Nginx
おさえておきたい料金体系
基本無料。
クレカ登録をすると稼働時間の増加以外にもアドオンの追加が可能になる。Freeプランではいくつか機能制限があります。
アカウント毎に、アプリケーションは月に550時間までの稼働時間が割り当てられる
アカウントにクレジットカードを紐付けると1000時間に増える
公開しているアプリケーションに30分間アクセスがないと、スリープモードに移行する有料プランになると上記制限がすべてなくなる($25/月〜)
詳細はこちら
デプロイ方法
イメージ:gitのherokuリポジトリを本番環境へデプロイするだけ
0. Herokuアカウントの登録
(アカウントをもっていればスルーで)
以下ページよりアカウントを作成する
Heroku公式より1.HerokuCLIをローカル環境にインストールする
Herokuを使うにはHeroku CLIというアプリケーションをローカル環境にインストールする必要がある。
これをインストールすることでgitを使ってデプロイが可能になる。sudo snap install --classic heroku※上記コマンドはLinux系のUbuntuコマンドなため各自環境に沿ったコマンドを実施する必要あり詳細は公式で確認
2. Herokuへログイン
ローカル環境で以下コマンドを入力しHerokuへログインする
heroku login -iEnter your Heroku credentials. Email: Herokuに登録したメールアドレスを入力 Password: Herokuに登録したパスワードを入力 Logged in as 登録したメールアドレス //ログイン完了3.Herokuアプリケーションの作成
デプロイしたいアプリケーションのプロジェクト直下にて下記コマンドを実行。
heroku create アプリケーション名アプリケーション名が
https://Herokuアプリケーション名.herokuapp.com/とドメイン名になりますCreating ⬢ example.app.. ! ▸ Name example.app is already taken
heroku appsコマンドで作成したアプリが確認できれば作成完了4.リモートリポジトリherokuの確認
念の為git 環境にherokuリモートリポジトリがあるか確認
git remote -v5.Heroku設定ファイルの新規作成
プロジェクトルート直下に以下コマンドでProcfileを作成する
echo "web: vendor/bin/heroku-php-nginx -C nginx.conf public/" > ProcfileProcfileが以下のようになっているか確認
web: vendor/bin/heroku-php-nginx -C nginx.conf public/※今回はNginxサーバーですがapacheの場合は
echo "web: vendor/bin/heroku-php-apache2 public/" > Procfileで作成
Procfileを作業ブランチにコミット&プッシュし、ローカルmasterブランチへマージ
6.本番環境へデプロイする
いよいよデプロイといってもデプロイしたいmasterブランチへ移動して下記のコマンドを実行するだけ
git push heroku master1分ほど待ち、下記の表記がでればデプロイ完了
remote: Verifying deploy... done.このままだとURLにアクセスしてもエラーが出るので後ほど環境変数を設定する
URLを叩いて以下のエラーが出たら・・・
There's nothing here, yet.ブランチへ入力したURLが間違っている可能性があります。スペルミスを確認しましょうForbiddenProcfileの設定が原因の可能性があります。こちらもスペースやスペルミス、masterブランチにProcfileがあるかを確認しましょう。7.MySQLの導入
Herokuには複数のadd-onが用意されており、MySQLを使うための ClearDB MySQL をインストールする必要がある。
下記コマンドを実行。heroku addons:create cleardb:igniteこれでFreeプランのMySQLが追加される。
以下のエラーが出た場合はアカウントにクレジットカードの登録が必要
▸ Please verify your account to install this add-on plan (please enter a credit card) For more ▸ information, see https://devcenter.heroku.com/categories/billing Verify now at ▸ https://heroku.com/verifyあとは環境変数を設定するだけ
環境変数の設定
.envはgitignoreされているためherokuリポジトリには反映されません。
heroku環境に環境変数を直接設定する必要があります。
- 設定コマンド
heroku config:set 環境変数名=キー- 確認コマンド
heroku configAPP_KEYの設定
DockerPHPコンテナ内プロジェクトルート直下で
$ php artisan key:generate --show内容をコピーしてローカル環境プロジェクトルート直下で下記コマンドを入力
heroku config:set APP_KEY=base64:xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx設定した APP_KEY が設定されていればOK。
MySQLの設定
heroku configで環境変数を確認。
cleardbのadd-onを追加しているためCLEARDB_DATABASE_URL:という環境変数が自動で設定されている。CLEARDB_DATABASE_URL: mysql://<ユーザー名>:<パスワード>@<ホスト名>/<データベース名>?reconnect=trueこれをもとに各環境変数を設定
$ heroku config:set DB_CONNECTION=mysql $ heroku config:set DB_DATABASE='<データベース名>' $ heroku config:set DB_USERNAME='<ユーザー名>' $ heroku config:set DB_PASSWORD='<パスワード>' $ heroku config:set DB_HOSTNAME='<ホスト名>' $ heroku config:set DB_PORT='3306'その他の環境変数
APP_URL
$ heroku config set:https://アプリケーション名.herokuapp.comslack認証系
SLACK_KEY=ローカル環境の`.env`の記述と同じ SLACK_REDIRECT_URI=ローカル環境の`.env`の記述と同じ SLACK_SECRET=ローカル環境の`.env`の記述と同じS3系
AWS_ACCESS_KEY_ID=ローカル環境の`.env`の記述と同じ AWS_BUCKET=ローカル環境の`.env`の記述と同じ AWS_DEFAULT_REGION=ローカル環境の`.env`の記述と同じ AWS_SECRET_ACCESS_KEY=ローカル環境の`.env`の記述と同じその他の設定方法
Herokuのビルドに関する設定
buildpackを追加する
Herokuダッシュボード内の上部メニューのSettingsを選択
Add buildpackの選択
node.jsの選択
Save changesで完了
PHPの選択
Save changesで完了
* heroku/nodejs * heroku/phpが表示されれば、buildpackの追加は完了
データベースのマイグレーション
Herokuからデータベース(MySql)に接続できるよう設定済みですが、まだテーブルを作成していません。
そこで、Laravelのマイグレーションコマンドを使ってテーブルを作成します。
以下コマンドを実行してください。$ heroku run php artisan migrate —seedheroku run (実行したいコマンド)で、Heroku上でコマンドを実行できます。
コマンドを実行すると、以下が表示されるので、yesと入力してエンターキーを押してください。Do you really wish to run this command? (yes/no) [no]:以下のように各テーブルのマイグレーションが完了した旨のメッセージが表示されれば問題ありません。
Migration table created successfully. Migrating: 2014_10_12_000000_create_users_table Migrated: 2014_10_12_000000_create_users_table (0.1 seconds) Migrating: 2014_10_12_100000_create_password_resets_table Migrated: 2014_10_12_100000_create_password_resets_table (0.04 seconds)Mysql接続コマンド
mysql -h <DB_HOSTNAME> -u <DB_USERNAME> -p -D <DB_DATABASE>作業内容を本番環境へ反映したいとき
ローカルのmasterブランチに変更内容を反映させ
git push heroku masterをするだけHeroku環境内に入るコマンド
heroku run bash共同開発者の追加
- Heroku にログインし、任意のサービスを選択
- 上部メニューの
accessを選択Add collaboratorを押下し、共同開発者のアカウントのメールアドレスを入力後、save changeを押下- 招待者のメールアドレスが追加されていることを確認
- 招待者はメールの案内に沿ってHerokuにアクセス
これでデプロイやHeroku環境系の操作が可能になります。
参考
- 投稿日:2020-08-20T12:59:55+09:00
【PHP】配列keyの挙動について
配列のkeyはint型かstring型の2種類
整数を配列のkeyに指定した場合、int型として扱われるため注意が必要です。
$array1 = [ '1983' => 'ファミコン', '1989' => 'ゲームボーイ', '1994' => 'プレイステーション', ]; var_dump(array_keys($array1)); // 実行結果 array(3) { [0]=> int(1983) [1]=> int(1989) [2]=> int(1994) }stringで指定していた場合でもkeyにするとint型になる
// keyをstring型で指定しておく $key1 = (string)'1983'; $key2 = (string)'1989'; $key3 = (string)'1994'; var_dump($key1); var_dump($key2); var_dump($key3); //var_dumpの結果 string(4) "1983" string(4) "1989" string(4) "1994" //stringで指定した変数をkeyにして配列を作成 $array1 = [ $key1 =>'ファミコン', $key2 => 'ゲームボーイ', $key3 => 'プレイステーション', ]; // stringで指定していた年数がint型になっている。 var_dump(array_keys($array1)); array(3) { [0]=> int(1983) [1]=> int(1989) [2]=> int(1994) }float型、8進数の場合
$array = [ 1.2 => 'foo', 2.6 => 'bar', 0332 => 'hoge', ]; var_dump($array); // 小数点切り捨ての10進数へ変換される array(3) { [1]=> string(4) "foo" [2]=> string(4) "bar" [218]=> string(4) "hoge" }整数にしたくない場合
文字列を連結しておく
例:「S_01」、「02A」など
ハッシュ化しておく
- 投稿日:2020-08-20T12:22:50+09:00
PHP基礎④
- 投稿日:2020-08-20T08:12:07+09:00
PHPでDBに接続、CRUDを利用して掲示板を作る② Readについて
前回(https://qiita.com/progterry/items/2f82b82a5118c16010a0)はPHPでDBに接続、CRUDのCreateの機能を実装するところまでお話をしました。
今回はRead機能について書いていこうと思います。そもそもReadとは?
Readとは、掲示板の機能で必須とされるCRUDの中の1つです。
CRUDはそれぞれ、
Create
Read
Update
Delete
の頭文字を取っています。それぞれの単語の具体的な機能に関しては前回の記事を参照。実際のコード
<?php $dsn = 'mysql:dbname=test_bbs2; host=localhost'; $username= 'root'; $password= 'root'; try{ $dbh = new PDO($dsn, $username, $password); echo "接続成功"; echo "<br>"; } catch(PDOException $e){ echo "失敗:" . $e->getMessage() . "\n"; exit(); } //SELECT文を変数に格納 $sql = "SELECT * FROM contacts"; //SQLステートメントを実行し、結果を変数に格納 $stmt = $dbh->query($sql); //foreach文で配列の中身を一行ずつ出力 foreach ($stmt as $row){ echo "名前:" . $row['submit_name'] . ':' . "発言:" . $row['submit_content']; echo '<br>'; } ?> <a href="index.php">トップへ戻る</a>こまかく見ていきましょう。
DB接続までは前回記事と同様のため省略します。
毎回DB接続を行うんだ、ということさえ覚えておいたらいいと思います。次に、
//SELECT文を変数に格納 $sql = "SELECT * FROM contacts";この部分は変数sqlに、データベースのcontactsテーブルから取り出した内容をいれています。
SELECT * FROM contacts
この部分はPHPではなく、SQLの書き方になっているので注意です。
アスタリスク* マークは、「すべてを」という意味になっています。
このコードは、contactsテーブルから、制限なくすべてのデータを取り出すという意味です。次に、
//SQLステートメントを実行し、結果を変数に格納 $stmt = $dbh->query($sql);この部分をみます。
ここでは右辺の処理を、stmtに代入しています。
CRUD処理を探しているとやたらとこの$stmtが出てきます。stmtはおそらくstatementの略で、よく使われる変数名みたいです。$dbh->query($sql);では、queryで、$sqlの中のSQLを実行し、オブジェクトとして返します。
参考(https://www.php.net/manual/ja/pdo.query.php)言い換えると、このqueryを行うことでsqlが目的の形になるということです。
最後に、
//foreach文で配列の中身を一行ずつ出力 foreach ($stmt as $row){この部分で、出力します。$stmtを$rowにしていますが、$rowの部分の変数名は何でもいいです。その後の部分とつじつまが合えば。
以上、このような形でRead機能が実装できました。
- 投稿日:2020-08-20T08:07:06+09:00
PHPの定数について
定数とは
宣言時に決めた値を再定義できない
PHPで定数を定義する方法2つ
define()で定数を定義するdefine('定数名', '値');PHP7〜 配列定数を定義できるようになった。
// 定数をクラス外に定義 define('CONSTANT', ['key1' => 'hoge', 'key2' => 'fuga']); class Sample { function printConst() { // クラス内から定数にアクセスする場合 print_r(CONSTANT); } } $sample = new Sample(); $sample->printConst(); // CONSTANTが出力される // クラス外から定数にアクセスする場合(同じ) print_r(CONSTANT); // CONSTANTが出力されるconstで定数を定義する
const '定数名' = '値';
PHP5.3 以上で使える。
PHP7〜 配列定数を定義できるようになった。
constはクラス定数を定義できる。class Sample { // 定数をクラス内に定義 const CONSTANT = ['key1' => 'hoge', 'key2' => 'fuga']; function printConst() { // クラス内から定数にアクセスする場合 print_r(self::CONSTANT); } } $sample = new Sample(); $sample->printConst(); // CONSTANTが出力される // クラス外から定数にアクセスする場合 print_r(Sample::CONSTANT); // CONSTANTが出力される
define()とconstの違い
define()は関数なので、constの方が高速に処理される。define()は変数や関数の戻り値を使えて、constでは使えない。$func = function(){ return '定数'; }; define('CONST_DEFINE', $func()); echo CONST_DEFINE; // 定数が出力される // 定数式に無効なものが含まれているという以下のエラーで終了する // Fatal error: Constant expression contains invalid const CONST_CONST = $func(); echo CONST_CONST;
define()はif文やfunctionの中でも使える。
- 投稿日:2020-08-20T01:12:24+09:00
amazonlinux2のhttpd + php7.4で「Uncaught Error: Call to undefined function simplexml_load_string」が出た場合の対処法
エラー
amazonlinux2で動くwordpressにあるテーマをインストールしたら以下のエラーに遭遇。
Uncaught Error: Call to undefined function simplexml_load_stringググった結果、どうやらSimpleXMLモジュールが入っていないとのこと。
動作環境
$ php -v PHP 7.4.7 (cli) (built: Jul 2 2020 23:17:59) ( NTS ) Copyright (c) The PHP Group Zend Engine v3.4.0, Copyright (c) Zend Technologies $ amazon-linux-extras | grep enabled 24 epel=latest enabled [ =7.11 =stable ] 42 php7.4=latest enabled [ =stable ] $ yum list installed | grep php php-cli.x86_64 7.4.7-1.amzn2 @amzn2extra-php7.4 php-common.x86_64 7.4.7-1.amzn2 @amzn2extra-php7.4 php-fpm.x86_64 7.4.7-1.amzn2 @amzn2extra-php7.4 php-json.x86_64 7.4.7-1.amzn2 @amzn2extra-php7.4 php-mbstring.x86_64 7.4.7-1.amzn2 @amzn2extra-php7.4 php-mysqlnd.x86_64 7.4.7-1.amzn2 @amzn2extra-php7.4 php-pdo.x86_64 7.4.7-1.amzn2 @amzn2extra-php7.4対処方法
amazon-linux-extrasでepelを有効化して、php-xmlをインストールする。
sudo yum install php-xml -ySimpleXMLが読み込まれていることを確認する。
$ php -i | grep -i simplexml /etc/php.d/20-simplexml.ini SimpleXML SimpleXML support => enabledそれから、あるWebページでモジュールの読み込み順番が大切との記述を発見。
この原因がなかなかわからず、権限変えたり色々やりましたが、結論としてモジュールを読み込む順番が大切でした。
simplexml.so を実行するためには、別の拡張モジュールが必要になるため、そのモジュールよりも後に拡張モジュールを読み込まないとエラーになる、ということのようです。そのため、simplexmlモジュールの読み込み順番の調整する。
mv /etc/php.d/{20,40}-simplexml.ini最後に、php-fpmとhttpdを再起動する
sudo systemctl restart php-fpm sudo systemctl restart httpdこれでエラーが解消された。
初め、php-fpmが動いていることに気づかず、httpdだけ再起動しても反映されなくて焦った。
参考
- 投稿日:2020-08-20T00:59:36+09:00
【Xdebug】VSCODE+PHP Laravel+Windows+Xamppでデバッグ実行
環境
Windows10 x64
VisualStudio Code 1.47.3
Xampp v3.2.4 (PHP 7.4.7)
VSCODEプラグイン PHP Debug v1.13.0(本記事でインストール~設定します)Xdebugインストールと設定
①VSCODEでPHP Debugをインストール
②php.iniに下記を追記
※ C:\xampp\php\ext\php_xdebug.dllが存在しているか確認してください
C:\xampp\php.inizend_extension = "C:\xampp\php\ext\php_xdebug.dll" [XDebug] xdebug.remote_autostart = 1 xdebug.profiler_append = 0 xdebug.profiler_enable = 0 xdebug.profiler_enable_trigger = 0 xdebug.profiler_output_dir = "c:\xampp\tmp" xdebug.remote_enable = 1 xdebug.remote_handler = "dbgp" xdebug.remote_host = "127.0.0.1" xdebug.remote_log="c:\xampp\tmp\xdebug.txt" xdebug.remote_port = 9000 xdebug.trace_output_dir = "c:\xampp\tmp" xdebug.remote_cookie_expire_time = 36000③「上部メニュー→実行→構成を追加」からlaunch.jsonを下記のようにする。
既に実行情報が記述されている場合は良い感じにマージする
launch.json{ "version": "0.2.0", "configurations": [ { "name": "Listen for XDebug", "type": "php", "request": "launch", "port": 9000 }, { "name": "Launch currently open script", "type": "php", "request": "launch", "program": "${file}", "cwd": "${fileDirname}", "port": 9000 } ] }デバッグ実行してみる
①左メニュー→デバッグ(再生アイコンに虫が乗っているアイコン)を選択して、構成が「Listen for Xdebug」が選択されているのを確認
②あとはブレークポイントを仕掛けて「F5」でデバッグ実行
Laravelでも動作確認済み








