- 投稿日:2020-02-18T22:46:05+09:00
Docker上でPHP拡張モジュール『GD』を有効化する
この記事ではDocker上でPHP拡張モジュール『GD』を有効化する方法をお伝えします。
どうしてGDの有効化が必要になったか
LaravelとVueを用いたSPAを勉強したく、『Vue + Vue Router + Vuex + Laravelで写真共有アプリを作ろう』に取り組んでいました。
(9)写真投稿APIでテストを実行した際に
Error: Call to undefined function Illuminate\Http\Testing\imagecreatetruecolor().
というエラーで行き詰まり、原因を調査したところPHP拡張モジュール『GD』の有効化が必要との情報にたどり着きました。環境
version PHP 7.4.1 Laravel 6.15.0 Docker for Mac 19.03.5 GD有効化の方法
DockerファイルにGDの有効化、必要なライブラリのインストールの部分を記載することでGDを有効化できます。
有効化した後、再ビルドすることで正しく動作するようになります。まずはGDが使えない状態のDockerfileをご紹介します。
DockerfileFROM php:7.4.1-fpm COPY install-composer.sh / RUN apt-get update \ && apt-get install -y wget git unzip libpq-dev \ && : 'Install Node.js' \ && curl -sL https://deb.nodesource.com/setup_12.x | bash - \ && apt-get install -y nodejs \ && : 'Install PHP Extensions' \ && docker-php-ext-install -j$(nproc) pdo_pgsql \ && : 'Install Composer' \ && chmod 755 /install-composer.sh \ && /install-composer.sh \ && mv composer.phar /usr/local/bin/composer WORKDIR /var/www/html/vuesplash【参考】
Vue + Vue Router + Vuex + Laravelで写真共有アプリを作ろう (3) SPA開発環境とVue Routerこれを下記のように変更します。
:Dockerfile FROM php:7.4.1-fpm COPY install-composer.sh / RUN apt-get update \ && apt-get install -y wget git unzip libpq-dev libfreetype6-dev libjpeg62-turbo-dev libpng-dev \ && : 'Install Node.js' \ && curl -sL https://deb.nodesource.com/setup_12.x | bash - \ && apt-get install -y nodejs \ && : 'Install PHP Extensions' \ && docker-php-ext-install -j$(nproc) pdo_pgsql \ && docker-php-ext-configure gd --with-freetype --with-jpeg \ && docker-php-ext-install -j$(nproc) gd \ && : 'Install Composer' \ && chmod 755 /install-composer.sh \ && /install-composer.sh \ && mv composer.phar /usr/local/bin/composer WORKDIR /var/www/html/vuesplash変更点は3行です。
まずは5行目。
- && apt-get install -y wget git unzip libpq-dev \ + && apt-get install -y wget git unzip libpq-dev libfreetype6-dev libjpeg62-turbo-dev libpng-dev \
libfreetype6-dev
、libfreetyep6-dev
、libjpeg62-turbo-dev
、libpng-dev
の4つのライブラリを追加しています。【参考】
docs/php at master · docker-library/docs
2点目の変更点は、変更後のファイル11行目に新たに一行挿入しています。
+ && docker-php-ext-configure gd --with-freetype --with-jpeg \PHP7.4系では
docker-php-ext-configure
の引数が変更されているので注意が必要です。【参考】
【PHP】Docker PHP7.4系でgdをインストールしてimagecreatefromjpegを使う
docs/php at master · docker-library/docs
最後に変更後のファイルの12行目のように、GDのインストールコマンドを追加して変更完了です。
+ && docker-php-ext-install -j$(nproc) gd \【参考】
docs/php at master · docker-library/docsまとめ
Laravelを勉強しているものの、基本的な言語仕様は同じだろうと高をくくっており、PHP自体の構成や拡張モジュールについては全く勉強しておらず、長時間ハマり続けてしまいました…
これを機に基本的な言語仕様や拡張モジュールについても勉強していければと思います。
また、長時間ハマり続けた別の理由として、古い情報がうまくいかない場合が多かったこともあるので、今回の記事のように苦労して解決したことは積極的に記事にしていきたいです。
まだまだPHPもLaravelもDockerも未熟なので、誤りがありましたらご指摘いただけると幸いです。
参考
- 投稿日:2020-02-18T22:25:40+09:00
【基本文法編】Ruby/Python/PHPの違い
はじめに
個人的な学習のまとめです!
3つの言語の基本文法を学習したのでまとめてみました!1. 出力
Rubyputs "Hello, world"Pythonprint("Hello, world")PHPecho "Hello, world";2. 変数
Rubyvariable = "変数”Pythonvariable = "変数”PHP$variable = "変数”;3.プロパティ値の出力
Ruby# attr_accessor :name 等でゲッターを定義する puts person.namePython# def __init__ 等でゲッターを定義する print(person.name)PHPecho $person->name();4. If文
Rubyif number % 15 == 0 puts "FizzBuzz" elsif number % 3 == 0 puts "Fizz" elsif number % 5 == 0 puts "Buzz" else puts number endPythonif number % 15 == 0: print("FizzBuzz") elif number % 3 == 0: print("Fizz") elif number % 5 == 0: print("Buzz") else: print(number)PHPif (number % 15 == 0){ echo "FizzBuzz"; } elseif (number % 3 == 0){ echo "Fizz"; } elseif (number % 5 == 0){ echo "Buzz"; } else { echo $number; }5. 配列/ハッシュ編
Ruby# 配列 array = ["赤", "青", "黄"] # ハッシュ hash = {"大阪府": "大阪", "愛知県": "名古屋", "東京都": "東京?"}Python# リスト lists = ["赤", "青", "黄"] # 辞書 dict = {"大阪府": "大阪", "愛知県": "名古屋", "東京都": "東京?"}PHP//配列 $array = ["赤", "青", "黄"]; //連想配列 $associative_array = [ "大阪府" => "大阪", "愛知県" => "名古屋", "東京都" => "東京?" ];6. 繰り返し構文
6-1.ループ処理
Rubyi = 1 while i <= 100 do # 処理 i += 1 endPythoni = 1 while i <= 100: # 処理 i += 1 for i in range(1, 101): # 処理PHPfor ($i = 1;$i <= 100;$i++){ //処理 }6-2. 反復処理(?)
Rubyarray.each do |value| #処理 end hash.each {|key, value| #処理 }Pythonfor value in lists: # 処理 for key in dict: # 処理PHPforeach($array as $value){ //処理 } foreach($associativeArray as $key => $value){ //処理 }7.関数定義
Rubydef hello # 処理 endPythondef hello(): # 処理 return # 戻り値PHPfunction hello() { // 処理 return // 戻り値 }8.クラスとインスタンス
Rubyclass Person @@number = 0 def self.classmethod # 処理 end def initialize(name) @name = name end person = Person.new("山田") endPythonclass Person: number = 0 @classmethod def classmethod(cls): # 処理 def __init__(self, name): self.name = name end person = Person("山田") endPHPclass Person { private static $number; private $name; public function static function classmethod(){ echo self::$number; } public function __construct($name){ $this->name = $name; } $person = new Person(); }9.ゲッターとセッター
Rubydef setName(name) @name = name end def getName @name end #あるいは attr_accessor :namePythondef __init__(self, name): self._name = name @property def name(self): return self.__name @name.setter def name(self, name): self.__name = namePHPpublic function setName($name) { $this->name = $name; } public function getName() { return $this->name; }10.最後に
1ブロックをどのように(end/インデント/{})指定するかに個性がある感じですね!
ご一読頂き、ありがとうございました!
- 投稿日:2020-02-18T21:58:19+09:00
instagram graph api 登録のちょっとした手順
案件でPHPの投稿を取得し、サイト内に表示させる機会がありました。
珍しくないことではあるが、実案件としては初めての機会であり、取得→表示に手こずったので(説明をきちんと読まない悪い癖のせいでもあるが)、忘れないようにメモしておきます。API
この類のAPIは以下が挙げられるかと思います。
https://web.analogstd.com/tips/posts/api/instagram-grapgh-api-facebook.phpInstagram API
提供元:Instagram
言わずもがなですが、2020年に利用停止となりますので、今から使う方はいないでしょう。。。
現状、使用しているサイトは見直しが必要ですねInstagram Graph API
提供元:Facebook
今回こちらを採用しました。トークンの取得
利用には、トークンの取得が必要です。今回、この手順はディレクターにおまかせして、諸々登録ご完了後に必要そうな情報を一式いただきました。
なので、今回は説明を割愛します。また、機会があれば改めてまとめることにしよう。
すごいめんどくさいらしいです。。。最終的に、必要となる情報は
無期限のトークン(場合によって、第3のトークンと呼ばれる。)
Instagramのビジネスアカウント(Facebookビジネスより登録。)
すで無期限のトークンを頂いていましたが、そもそもそれが何なのかわからなかったので、見直しがてら自分で作業を行いました。
無期限のトークンの取得
取得した
トークン2
を使って下記のurlにアクセスします。
https://graph.facebook.com/v3.0/me?access_token=【トークン2】
すると、オブジェクトが表示されるはずです。{ "name":"hoge", "id":"fuga" }
トークン2
とID
を使用して、下記にアクセスします。
https://graph.facebook.com/v4.0/【ID】/accounts?access_token=【トークン2】
(※vはバージョンです。適宜変更してください。自分はv4.0だったはず)
以下のように表示されたらおkです。{ "data":[ { "access_token":"fugafuga", "category":"", // 省略 }この
access_token
が第三のトークン(無期限のトークン)
と呼ばれる最終必要情報です!(ここまでが長い〜)
表示されたアクセストークンを、facebook for developerのアクセストークンデバッカーに入力して、諸々設定を確認
とりあえず、有効期限は受け取らないにしておくといいかと思います。
(この辺の作業、ディレクターに行っていただいたので詳細は割愛させてください。。。。)投稿の確認
問題なければ、instagramの投稿情報がもろもろ表示されるはずです。
{ "data": [ { "permalink_url": "https://facebookurl", "id": "000", "created_time": "2019-", "message": "hogehoge", // 略perma_linkにアクセスして、問題なく該当の投稿が表示されればおkです。
instagram ビジネスアカウント
無限のトークンの他に必要な情報です。下記、アクセスします。
https://graph.facebook.com/【アクセストークンデバッガーで確認できるページID】?fields=instagram_business_account&access_token=【無期限のトークン】
以下のように表示されたらおkです。"instagram_business_account": { "id": "1234567890" }, "id": "1234567890"出力
いよいよ出力します。
今回は、jsonとしてデータを受け取り、jsで表示処理を別途行います。(ajaxでとりあえずconsole出力してみましょう。)
こんな感じでしょうか。
(セキュリティの問題上、jsで処理するのではなく、PHPで処理しましょう。)get.php$accessToken = 'hogehoge'; // アクセストークン $businessId = '111111'; // ビジネスアカウントID $fields = 'media{caption,media_url,permalink,timestamp}'; // 取得するデータのパラメータ $url = 'https://graph.facebook.com/v4.0/'.$businessId."?fields=name%2Cmedia.limit(4)%7Bcaption%2Clike_count%2Cmedia_url%2Cpermalink%2Ctimestamp%2Cthumbnail_url%2Cmedia_type%2Cusername%7D&access_token=".$accessToken; $jsonData = file_get_contents($url); $json = json_decode($jsonData, true); echo json_encode($json["media"]["data"]);最後に
記事の書き始めから、2週間ほど経過しており少しすでに曖昧になっている点も有りました。(冒頭、忘れないためのメモ書きという趣旨を書いていましたが。。。)間違いがありましたら、申し訳ありません。
- 投稿日:2020-02-18T20:32:15+09:00
PHPを使ってPDFを作成する
今回使うライブラリは、既存のPDF文書をテンプレートとして引用できるので、静的なレイアウト作成や細かい調整などはwordやExcelで行うことができます。
動的なデータに関しては、座標指定で配置可能ですライブラリとフォントをダウンロードする
それぞれ解凍して、任意の場所に配置してください。
(あとでパスを指定すればいいのでどこでもOK)実際のコード
write_pdf.php// 文字コードをUTF-8に mb_internal_encoding("UTF-8"); // クラスをインポート use setasign\Fpdi\TcpdfFpdi; // TCPDFの読み込み require_once('./TCPDF/tcpdf.php'); // FPDIの読み込み require_once('./FPDI/src/autoload.php'); /* IPA Font (IPA Fonts 4 fonts package) IPAfont00303.zip |--Readme Readme_IPAfont00303.txt |--IPA Font License Agreement v1.0 IPA_Font_License_Agreement_v1.0.txt |--IPAGothic ipag.ttf |--IPAPGothic ipagp.ttf |--IPAMincho ipam.ttf |--IPAPMincho ipamp.ttf */ // フォントの読み込み $font_path = './TCPDF/fonts/ipam.ttf'; // フォントを適用 $font = new TCPDF_FONTS(); $fontR = $font->addTTFfont($font_path); // PDFの読み込み $base_pdf = './PDF/sample.pdf'; // 出力するPDFの初期設定 $pdf = new TcpdfFpdi('L', 'mm', 'A4'); $pdf->setPrintHeader( false ); $pdf->setPrintFooter( false ); // テンプレートPDFの読み込み $pdf->setSourceFile($base_pdf); //以下PDF--------------------------------------------------------------- //1ページ目-------------------------------------------------------------- $pdf->AddPage('P', 'A4'); $pdf->useTemplate($pdf->importPage(1)); $pdf->SetFont($fontR , '', 9,'',true); $pdf->Text( 170 , 28 ,"Test"); //2ページ目-------------------------------------------------------------- $pdf->AddPage('P', 'A4'); $pdf->useTemplate($pdf->importPage(2));
- 投稿日:2020-02-18T19:39:54+09:00
Google Cloud StorageとCloud SQL利用するPHPウェブサーバー
VMインストール作成
php-vm
Name: php-vm
Region: us-central1
Zone: us-central1-a
Boot disk: Debian GNU/Linux 9 (stretch)
Access scopes: Allow default access
Firewall: Allow HTTP traffic(受信HTTPトラフィックを許可します)
更に、ゾーン間のVMインスタンスを接続を参考
利用情報: VM IP addressをコピーCloud Storageにデータ保存
Cloud Shell開いてgsutilコマンドラインでBucket作成
mb - Make buckets
Synopsisgsutil mb [-b <on|off>] [-c class] [-l location] [-p proj_id] [--retention time] url...LOCATION変数設定するコマンド
export LOCATION=us
or
export LOCATION=eu
or
export LOCATION=asia
bucket作成するコマンド
gsutil mb -l $LOCATION gs://$DEVSHELL_PROJECT_ID
or
gsutil mb -l us gs://bucket-name
DEVSHELL_PROJECT_ID固定変数の値はproject ID
更にgsutilのコマンドガイドを参考cp - Copy
Synopsisgsutil cp [OPTION]... src_url dst_url gsutil cp [OPTION]... src_url... dst_url gsutil cp [OPTION]... -I dst_url[gs://cloud-training/gcpfci/]は公開するストレージデータ
データ情報を取得するコマンド
gsutil ls gs://cloud-training/gcpfci
banner imageを作成
gsutil cp gs://cloud-training/gcpfci/my-excellent-blog.png banner-image.png
[gs://cloud-training/gcpfci/my-excellent-blog.png]:公開させる画像
[banner-image.png]:バナー画像
bucketへバナー画像をコピー
gsutil cp banner-image.png gs://$DEVSHELL_PROJECT_ID/myExcellentBlog.png
[gs://$DEVSHELL_PROJECT_ID/]:画像を保存するbucketGcloud SQL作成
データベース作成
Choose your database engine: MySQL
Instance ID: php-sql
Root password:@php-sql
(自分が決める値)データベース設定
- Public IP addressをコピー
- user accountを作成:usersタブを開いて以下の情報を設定(自分が決める値)
- User name:
phpsqluser
- Password:
phpsqluser
- Networkを設定:Connections タブを開いて以下の情報を設定
- name:
php web
- Password:
[VM IP address]/32
(32はデフォルト値)VMインスタンスでPHPウェブサーバー構築しGCSとGSQL利用
PHPウェブサーバーインストール
php-vmのSSHを開いてPHPウェブサーバーインストール
sudo apt-get update
sudo apt-get install apache2 php php-mysql -y
sudo service apache2 restartGSQL利用
ソースフォルダへディレクトリー
cd /var/www/html
index.phpファイルを修正する為、nanoコマンドで開く
sudo nano index.php
以下のように編集するindex.php<html> <head><title>Welcome to my excellent blog</title></head> <body> <h1>Welcome to my excellent blog</h1> <?php $dbserver = "CLOUDSQLIP"; $dbuser = "blogdbuser"; $dbpassword = "DBPASSWORD"; // In a production blog, we would not store the MySQL // password in the document root. Instead, we would store it in a // configuration file elsewhere on the web server VM instance. $conn = new mysqli($dbserver, $dbuser, $dbpassword); if (mysqli_connect_error()) { echo ("Database connection failed: " . mysqli_connect_error()); } else { echo ("Database connection succeeded."); } ?> </body></html>「Ctrl+O → Enter → Ctrl+X」で編集が終わり
resultDatabase connection failed: ...データベースへ接続できる為、index.phpファイル直し
sudo nano index.php
以下の情報を修正
dbserver = "DBのPublic IP address";
dbuser = "phpsqluser";
dbpassword = "phpsqluser";サーバー再起動
sudo service apache2 restart
resultDatabase connection succeeded.GCS利用
index.phpファイルを開いてindexページにストレージから取る画像を表示する
sudo nano index.php
index.php<img src='myExcellentBlog.pngのLink URL'>
- 投稿日:2020-02-18T15:01:31+09:00
PHP+AjaxでHEAD内のOGP情報を取得する方法
[PR] e-zines(イージンズ) - 新しいスタイルでトレンドをお送りする無料のメールマガジン
いろいろな技術系のブログにOGP情報の取得方法が載ってるのだけれど
キュレーションサイトによって記事のOGP記述方法が様々なので自分で書いてみた適当なファイル GetOGP.php とかにして ajax から呼ぶとほぼほぼ取得できます
取得できないサイト(記事)があったらコメントに書いてくれれば直しますYO!GetOGP.php<?php try { header('content-type: application/json; charset=utf-8'); $dat = $_GET["url"]; if (isset($dat) and preg_match("/^https?:/", $dat)) { $ctx = stream_context_create(array( 'http' => array( 'method' => 'GET', 'header' => 'User-Agent: Mozilla/5.0 (Macintosh; Intel Mac OS X 10_11_2) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/47.0.2526.106 Safari/537.36') ) ); $temp = file_get_contents($dat, false, $ctx); $temp = mb_convert_encoding($temp, "UTF-8", "auto"); preg_match('/(<head|<HEAD)(.*)(head>|HEAD>)/s', $temp, $head); $html = $head[0]; // ogp $ogp = null; preg_match_all("<meta\s*property=[\"']og:([^\"']+)[\"']\s*content=[\"']([^\"']+)[\"']\s*>", $html, $ogp); for( $i = 0; $i < count($ogp[1]); $i++ ) { $result[$ogp[1][$i]] = $ogp[2][$i]; } $ogp = null; preg_match_all("<meta\s*content=[\"']([^\"']+)[\"']\s*property=[\"']og:([^\"']+)[\"']\s*>", $html, $ogp); for( $i = 0; $i < count($ogp[1]); $i++ ) { $result[$ogp[2][$i]] = $ogp[1][$i]; } $ogp = null; preg_match_all("<meta\s*name=[\"']og:([^\"']+)[\"']\s*content=[\"']([^\"']+)[\"']\s*>", $html, $ogp); for( $i = 0; $i < count($ogp[1]); $i++ ) { $result[$ogp[1][$i]] = $ogp[2][$i]; } // twitter $twitter = null; preg_match_all("<meta\s*name=[\"']twitter:([^\"']+)[\"']\s*content=[\"']([^\"']+)[\"']\s*>", $html, $twitter); for($i = 0; $i < count($twitter[1]); $i++) { $result2[$twitter[1][$i]] = $twitter[2][$i]; } if (count($twitter[1]) == 0) { preg_match_all("<meta\s*content=[\"']([^\"']+)[\"']\s*name=[\"']twitter:([^\"']+)[\"']\s*>", $html, $twitter); for($i = 0; $i < count($twitter[1]); $i++) { $result2[$twitter[2][$i]] = $twitter[1][$i]; } } if (!isset($result['title'])) { $result['title'] = $result2['title']; } if (!isset($result['url'])) { if (isset($result2['url'])) { $result['url'] = $result2['url']; } else { $result['url'] = $url; } } if (!isset($result['image'])) { if (isset($result2['image:src'])) { $result['image'] = $result2['image:src']; } else { $result['image'] = $result2['image']; } } if (!isset($result['description'])) { $result['description'] = $result2['description']; } if (!isset($result['site_name'])) { $result['site_name'] = $result2['site']; } $res = [ 'title' => str_replace('"', '”', $result['title']), 'url' => str_replace('http://', 'https://', $result['url']), 'image' => str_replace('http://', 'https://', $result['image']), 'description' => str_replace('"', '”', $result['description']), 'site_name' => str_replace('"', '”', $result['site_name']), ]; // success echo json_encode($res); } else { // fail echo json_encode(['status' => 'error']); } } catch (Exception $e) { // fail echo json_encode([ 'status' => 'fatal error:'.$e->getMessage(), ]); }では、また
[PR] e-zines(イージンズ) - 新しいスタイルでトレンドをお送りする無料のメールマガジン
- 投稿日:2020-02-18T13:43:27+09:00
ラズパイでPHPを導入してみた
はじめに
まずは恒例の
sudo apt-get updateをしてからPHPのインストール
sudo apt-get install php php-xmlインストールが完了したら、バージョンを確認してみる
php -vとりあえずなにか表示
phpinfo();を表示してみる
HTMLのときと同じようにファイルを作って中身を入力していく。ファイル名は「test」にする。pi@raspberrypi:~ $ sudo vim /var/www/html/test.php<?php phpinfo(); ?>で、HTMLと同じ時の要領で
http://192.168.*.*/test.php
で表示してみる。
・
・・
・・・
なぜか表示できない...
どういう訳かそのまま
<?php
phpinfo();
?>
が表示されちゃう...解決策
色々調べて試してみたが、どうやってもうまく行かないので最後の手段として一回全部削除してみる…
sudo apt-get --purge remove php*そして最初から同じ手順を試してみる
原因はよくわからないけど、詰んだらとりあえず真っさらな状態にして一度試すしかない(正しいかわからないけど)
- 投稿日:2020-02-18T12:34:46+09:00
iksm_sessionを取得するための認証リンク
ほしかったもの
Swiftでニンテンドーアカウントにアクセスしてiksm_sessionを取得したかった。
splatnet2statinkでは実装されているのだが、そのコードをPHP向けに書き直した感じです。
ただ、これだけでは足りなくてNexus氏のflapg APIとfrozenpandaman氏のs2s APIが別途必要になります。
実装
PHPでイカのコードを書くだけ。
<?php function urlsafe_b64encode($val) { $val = base64_encode($val); return str_replace(["/","+","="], ["_","-",""], $val); } $auth_state = urlsafe_b64encode(random_bytes(36)); $auth_code_verifier = urlsafe_b64encode(random_bytes(32)); $auth_cv_hash = hash("sha256", $auth_code_verifier); $auth_code_challenge = urlsafe_b64encode(hex2bin($auth_cv_hash)); $base_url = "https://accounts/nintendo.com/connect/1.0.0/authorize?"; $base_url = "https://accounts.nintendo.com/connect/1.0.0/authorize?"; $param = array( "state" => $auth_state, "redirect_uri" => "npf71b963c1b7b6d119://auth", "client_id" => "71b963c1b7b6d119", "scope" => "openid user user.birthday user.mii user.screenName", "response_type" => "session_token_code", "session_token_code_challenge" => $auth_code_challenge, "session_token_code_challenge_method" => "S256", "theme" => "login_form" ); $auth_url = $base_url . http_build_query($param); $response = array( "auth_code_verifier" => $auth_code_verifier, "auth_url" => $auth_url); header('content-type: application/json; charset=utf-8'); echo(json_encode($response, JSON_UNESCAPED_SLASHES)); ?>リダイレクトURIがURLエンコードされてしまうので微妙にダサい感じになるがこれで動きます。
完成したもの
自分のリリースしたアプリでどうしてもそういう機能が欲しかったのでこういうのを完成させました。
AWS上のサーバなのでご利用は計画的に。
- 投稿日:2020-02-18T11:45:36+09:00
PHPerからGo使いへ
Goとは?
・Goは2009年にGoogleが開発したオープンソースプロジェクトのプログラミング言語です。
特徴
- いわゆる静的言語 ただし型推論は強め
- シンプルな記述
- ループ処理はfor文だけ
- 他の言語で用意されている継承の概念がない
- 並行処理の記述が簡単
- 実行速度やコンパイル速度が早い
触ってみた所感
- Javaなどの他の静的言語に比べて記述が簡単!
- PHPと比べると実行速度早いのは良いです。
- よくも悪くもコンパイルが必要な言語なので、実行前にポカミスが洗い出されるのは良いです。
- シンプルで出来ることが他の言語に比べ限られているので、記述ややり方について悩むことは少ないのでは、と想像。
サンプルコード
fizzbuzz.gopackage main //ライブラリの読み込み。これをPHPで言う組み込み関数的な。 import ( "fmt" "strconv" ) //main関数から実行されます。 //Goにはクラスの概念はありません。またファイル実行のためには必ずfunc main()が必要です。 func main(){ //厳密な変数宣言。 var num int num = 10000 //main関数から別の関数を呼び出し。 message := fizzbuzz(num) fmt.Println(message) } //引き数に型の指定はマスト。 //返り値がある場合には返り値の型も書かないといけません。 func fizzbuzz(num int) string{ var message string //このように省略して変数宣言もできます。型の指定も省略できます。 for i := 1; i <= num; i++{ if i % 3 == 0 && i % 5 == 0 { //文字列の結合は+を使います。 message = message + "FizzBuzz\n" } else if i % 3 == 0 { message = message + "Fizz\n" } else if i % 5 == 0 { message = message + "Buzz\n" } else { //整数と浮動小数点数のキャストは簡単なのですが、 //整数と文字列のキャストはこのように厳密にやらなくてはいけません。 var s string s = strconv.Itoa(i) message = message + s + "\n" } } return message }ちょっとした考察
- WEBアプリなどで言語の処理速度がボトルネックになることはまずない(DBがボトルネックになりやすい)ので、速度を目的にしてGoをチョイスするのは微妙かなと思いました。(DBとかが介在しない自動売買のBOTとかには良いです。)
- PHPにあってGoにないものとしてフレームワークの存在があります。 言語として記述をシンプルにしているのでフレームワークは(現状)不要、と言う考え方もできますが、 PHPなどの他の言語ではフレームワークを使用することによって、記述のシンプルさや統一性を担保しているとも言えるので、この点でもGoの優位性は微妙かなと思いました。(個人的にはGoそもそものシンプルさは好きです。)
- 投稿日:2020-02-18T11:08:47+09:00
【docker】ERROR:OCI runtime create failedが出る。
状況
DockerfileFROM php:7.3-fpm COPY php.ini /usr/local/etc/php/ RUN apt-get update \ && apt-get install -y zlib1g-dev libzip-dev mariadb-client \ && docker-php-ext-install zip pdo_mysql #Composer install RUN php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');" RUN php -r "if (hash_file('sha384', 'composer-setup.php') === 'e0012edf3e80b6978849f5eff0d4b4e4c79ff1609dd1e613307e16318854d24ae64f26d17af3ef0bf7cfb710ca74755a') { echo 'Installer verified'; } else { echo 'Installer corrupt'; unlink('composer-setup.php'); } echo PHP_EOL;" RUN php composer-setup.php RUN php -r "unlink('composer-setup.php');" RUN mv composer.phar /usr/local/bin/composer ENV COMPOSER_ALLOW_SUPERUSER 1 ENV COMPOSER_HOME /composer ENV PATH $PATH:/composer/vendor/bin RUN composer global require "laravel/installer"php:7.3-fpmのDockerfile下のように書き、
docker-compose up -d --build
すると、次のようなエラーが出る。ERROR: for php-fpm Cannot start service php-fpm: OCI runtime create failed: container_linux.go:344: starting container process caused "chdir to cwd (\"/var/www/html\") set in config.json failed: permission denied": unknown ERROR: Encountered errors while bringing up the project.
chdir to cwd (\"/var/www/html\")
などを見るとphp-fpmの作業ディレクトリの問題だろうと思いDockerfileを修正する。DockerfileWORKDIR /var/www今回はアプリを
/var/www
に置いているので、そこを作業ディレクトリに指定してみる。
再びdocker-compose up -d
してみると無事コンテナが起動する。原因
単純にDockerfileに作業ディレクトリの指定がなく、
/var/www/html
となっていたこと。
なぜ/var/www/html
となっていたかはわからない。デフォルトではそうなるのだろうか。
- 投稿日:2020-02-18T10:43:17+09:00
非階層クラスター分析のk-means法をPHPで作ってみた
非階層クラスター分析で代表的な手法のk-means法は、pythonのライブラリに存在したり、統計ソフトに標準機能として搭載されていることが多く、なじみの多い手法のようですが、実際のアルゴリズムを確認するために、(慣れている)PHPで作ってみました。
k-means法のアルゴリズムの理解は、こちらがわかりやすいです。
ソースは以下の通りです。
点を2次元平面に点在させて、それらのクラスターに分けます。
完全にランダムに配置させると、クラスター化の初期値依存が高くなるため、敢えていくつかの場所に集中して配置させるようにしました。<?php $max = 500; //領域の大きさ $margin = 50; //ランダムの配置するときの中心からの範囲 $dot_num_per_center = 30; //1中心点に配置するときの点の数 $center_num = 4; //中心点の数 $action_num = 5; //k-means実行回数 //点の配置 print "①この下の表が配置した点です。"; $dots = array(); print "<table>"; for ($i = 1; $i <= $center_num; $i++) { //中心点の位置をランダムに決める $center_x = rand($margin, $max - $margin); $center_y = rand($margin, $max - $margin); for ($j = 1; $j <= $dot_num_per_center; $j++) { //中心点を中心にmarginの範囲で点を決める $x = rand($center_x - $margin, $center_x + $margin); $y = rand($center_y - $margin, $center_y + $margin); $dots[] = ["x" => $x, "y" => $y]; print "<tr><td>{$x}</td><td>{$y}</td></tr>"; } } print "</table>"; //初期の重心を適当に決める(適当すぎて重心候補から外れてエラーになることがある) $gravity = []; for ($i = 1; $i <= $center_num; $i++) { $gravity[$i]["x"] = rand($margin, $max - $margin); $gravity[$i]["y"] = rand($margin, $max - $margin); } //k-means実行 for($num = 1; $num <= $action_num; $num++) { //各点の一番近い重心を決める foreach ($dots as $dot_key => $dot) { $min_length = 0; for ($i = 1; $i <= $center_num; $i++) { $length = calc_length($gravity[$i]["x"], $gravity[$i]["y"], $dot["x"], $dot["y"]); if($min_length === 0 || $min_length > $length) { $min_length = $length; $dots[$dot_key]["gravity_number"] = (int)$i; } } } //各重心の点の重心を再計算する $gravity = []; $count = []; foreach ($dots as $dot_key => $dot) { if(!isset($gravity[$dot["gravity_number"]]["x"])) $gravity[$dot["gravity_number"]]["x"] = 0; $gravity[$dot["gravity_number"]]["x"] += $dot["x"]; if(!isset($gravity[$dot["gravity_number"]]["y"])) $gravity[$dot["gravity_number"]]["y"] = 0; $gravity[$dot["gravity_number"]]["y"] += $dot["y"]; //核にある点の数 if(!isset($count[$dot["gravity_number"]]))$count[$dot["gravity_number"]] = 0; $count[$dot["gravity_number"]]++; } for ($i = 1; $i <= $center_num; $i++) { if(isset($gravity[$i]["x"]))$gravity[$i]["x"] /= $count[$i]; if(isset($gravity[$i]["y"]))$gravity[$i]["y"] /= $count[$i]; } } print "<br /><br /><br />②以下がクラスターに分けたデータです"; //それぞれの重心の点を表示する print "<table>"; foreach ($dots as $dot_key => $dot) { print"<tr><td>{$dot["x"]}".(str_repeat("</td><td>", (int)$dot["gravity_number"])).$dot["y"]."</td></tr>"; } print "</table>"; //長さを求める function calc_length($x1, $y1, $x2, $y2) { return sqrt(pow($x1 - $x2, 2) + pow($y1 - $y2, 2)); }データの見方
上記PHPを実行すると、上下に2つの表が出力します。(①②と表示しています)
データの点在確認
①はデータの点在を確認します。エクセルに貼り付けて、「散布図」にて確認出来ます。
クラスターの確認
②はクラスター分けされた状態を確認できます。同じくエクセルに貼り付けて、「散布図」にて確認出来ます。
課題
仮に決めた重心が完全ランダムですので、データの点在から離れすぎてエラーとなることがあります。。。
その時は、再度実行して下さい。
実際のk-means法では、仮決めの重心はデータの点在状況に応じて、ある程度領域を限定するものだとわかりました。