20200430のPHPに関する記事は18件です。

MAMP(FREE)のインストールから表示まで(MAC )

MAMPとは

MAMP(マンプ)とは、ローカル開発環境に必要なソフトウェア(Apache、MySQL、PHP)をパッケージ化したもので、macOS、Windows上で動作させることが出来る。
「Macintosh」「Apache」「MySQL」「PHP」の頭文字をとってMAMPと名付けられている。

MAMPのインストール

MAMPの公式サイトよりダウンロード(https://www.mamp.info/en/)
FREE Downloadをクリック
MAMP1.jpeg
MAMP & MAMPPRO5.7をクリック
MAMP2.png
クリックするとダウンロードが始まるので終わるまで待つ。
ダウンロードが終わったらファイルを解凍する。
MAMP3.png
MAMP4.png
MAMP5.png
続けるをクリックすると、使用許可を求められるので、特に問題なければ同意するをクリック
MAMP6.png
MAMP PROを一緒にインストールする場合はインストールをクリック。今回は、MAMP PROはインストールしないのでカスタマイズを選択し、MAMP PROのチェックを外しインストール。MAMP7.png
MAMP8.png
何もなければ無事にインストールが終了したと思います。

MAMPの起動

インストールされたMAMPを立ち上げるとこのような画面が出るので、起動するにはStart Serversをクリックします。
MAMP9.png
MAMP10.png
Apache MySQLが緑に点灯すれば起動成功です。ストップさせたい場合はStop Serversをクリックで終了します。

ブラウザに表示

ブラウザを開いて「localhost」もしくは「127.0.0.1」と入力します。
このような形で表示されると無事にローカルサーバーに表示できている事が確認できるかと思います。
image.png
これから初期設定等ありますが、とりあえず今回はここまでにします。
今回初投稿で見にくいところなどあったかと思いますので、徐々に改善していきたいとおもいます。
最後まで読んでいただいてありがとうございました!!

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

「破壊的メソッド」はRuby用語なのか?

昨日、「データサイエンティストが知るべき破壊的メソッドのすべて」という記事を書いたのですが、友人から次のような意見を貰いました。

微妙に気になったけど、「破壊的メソッド」「非破壊的メソッド」ってプログラミング全般でなくRuby用語で、かつ、「レシーバを変更するメソッド」っていう意味じゃない?
もしあえて名前で呼ぶなら、inplace methodが正しそう。(日本語は見つからない)
https://discuss.pytorch.org/t/what-is-in-place-operation/16244
https://ja.wikipedia.org/wiki/In-placeアルゴリズム

更に、例えばpandasでもinplaceという引数名が使われているので、データサイエンティスト向けならinplaceのほうが馴染みあるかもしれないとも言われました。

たしかに「破壊的」と調べて出てくる記事は、Rubyのものが多いように思います。少し気になったので、いろいろな言語のドキュメントで「破壊的(destructive)」「インプレース(in-place)」という単語で調べて比較してみました。

Pythonの場合: in-placeが優勢

ドキュメントを検索したところ、実際に「インプレース(in-place)」という単語がよく使われているようです。例えば「プログラミング FAQ」の中では次のようにあります。

文字列をインプレースに変更するにはどうしたらいいですか?¶

文字列はイミュータブルなので、それはできません。殆どの場合、組み立てたい個別の部品から単純に新しい文字列を構成するべきです。

一方で、「破壊的(destructive)」という単語も多少は使われています。例えばPython2.7のドキュメントには「破壊的に(destructively)」という単語があります。最新バージョンのドキュメントでは「消去して返します」とありますが、日本語の訳語が変わっただけでした。

集合のアルゴリズムで使われるのと同じように、 popitem() は辞書を破壊的にイテレートするのに便利です。辞書が空であれば、 popitem() の呼び出しは KeyError を送出します。

Python3.8でも「curses --- 文字セル表示を扱うための端末操作」の中に「非破壊的(non-destructive)」という単語が見つかりました。

ウィンドウを destwin の上に重ね書き (overlay) します。ウィンドウは同じサイズである必要はなく、重なっている領域だけが複写されます。この複写は非破壊的です。

少し離れた箇所に「破壊的(destructive)」もあります。

destwin の上にウィンドウの内容を上書き (overwrite) します。ウィンドウは同じサイズである必要はなく、重なっている領域だけが複写されます。この複写は破壊的です。

Rubyの場合: destructive methodという用語が説明されている

Official Ruby FAQの中に「What is a destructive method?」という項目が用意されていました。日本語版の訳は見つかりませんでした。

The plain version creates a copy of the receiver, makes its change to it, and returns the copy. The “bang” version (with the !) modifies the receiver in place.

説明の中に「in place」という単語も使われています。

ドキュメントではあまりヒットしなかったので、るびまも見てみます。やはり「破壊的」という単語がよく使われています。例えば「Ruby コードの感想戦 【第 2 回】 WikiR」より。

force_encoding は ! がついていないので名前だけではわかりづらいですが、破壊的なメソッドです。 そのため、戻り値を text に代入する必要はありません。これで十分です。

「6 月 10 日 午前の部」でin-placeという単語が使われている箇所もありました。

文法上、yield が先に入って、ブロックつき引数を後で導入したとき yield が邪魔になった。あと String で、in-place で mutate するしないがごっちゃになってよくない。Perl からもってきた組み込み変数の 98% は後悔してます。

PHPの場合: 両方とも併用されている

「in-place」と「destructive」という単語が両方とも使われているようです。これらの箇所の日本語への翻訳はまだ行われていない様子?

Ds\Sequence::sort」より

Sorts the sequence in-place, using an optional comparator function.

Ds\PriorityQueue::toArrayより。

注意:

This method is not destructive.

その他の言語

Rubyに影響を与えたSmalltalkも調べてみたかったのですが、はっきりしたこととは分かりませんでした。ただ、Smalltalk-72のドキュメントを見ると、non-destructiveという単語が少なくとも一箇所使われていました。

Note that you can make non-destructive text by using xor ink which complements the background so that reshowing the text crases it while restoring what was
underneath.

また、基本的に変数がイミュータブルなHaskellも調べてみたのですが、destructiveが「過去の互換性を切った言語仕様のアップデート」という意味で使われているものしか見つけられなかったのと、ドキュメント自体を読むのが今の私にとっては骨が折れそうだったので諦めました。

また、Rubyでは「destructive method」という固有名詞に近い使われ方をしているのに対して、他の言語のdestructiveは一般的な形容詞として使われているように見えます。もしかすると、「破壊的メソッド」というのはRubyのコミュニティで使われ始めた言葉が、日本語でプログラミング用語として認識されて広まったものなのかもしれません。機会があればまた調べてみます。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Amazon PA-API が v5になって使えなくなったから、スクレイピングして強引にデーターを持ってくるVBAを作った話

初めに

amazonPA-API楽天ブックス書籍検索APIに書籍やCD、DVDの情報を取りに行き、記事の文末にアフィリエイトのリンクを貼るためのHTMLを生成するツールをPHPで作っていました。

ツールの仕様は、本の見出しやISBN-10で検索し、amazonのAPIから必要な情報を取得した後に、ISBNを持って楽天APIに行って、楽天からも書籍データーを取得します。それを規定のHTMLの指定の場所に挿入して、1つのHTMLの塊として書き出し、それをコピペして使うというものです。

商品画像や本のタイトル、著者情報や価格はAmazonから引用したもので、それらをクリックするとAmazonの商品ページにジャンプし、楽天ショッピング用のボタンもあり、それを押すと、楽天の該当商品の画面にジャンプします。

ツールが動かないとの連絡

2020年3月中旬に、このツールが動かなくなったと各部署から連絡があり、調べるとAmazon PA-APIがv5にバージョンアップしていて、 PA-API v5への移行を2020年3月9日までに実施しなかった場合、現在のPA-APIはご利用をいただけなくなりますとありました。

▪️PA-API v5移行のご案内 (2020/3/9まで)
https://affiliate.amazon.co.jp/help/node/topic/GZBFW3F79Y7FADBL

もともとアカウントを管理しているのは、営業部門で、我々IT部門はツールを作っただけでした。
連絡も管理者にはメールが届いていたようですが、見事に見逃していたようで、こちらには連絡が一切ありませんでした。

ツールをPA-API 5.0に移行

amazonの移行ガイドには以下のように書かれています。
そのため、アカウントを移行してから新しい認証情報(AWSアクセスキーとAWSシークレットキー) を取得し、それをツールにセットしました。

現在お持ちのAWS認証情報 (AWSアクセスキーとAWSシークレットキー) は PA-API 5.0では使えません。
現在AWSの認証情報をお持ちの場合は、アカウントを移行してから新しい認証情報を作ることができます。

「リクエスト回数が多すぎる」というエラーで値が取れない

Error! RequestThrottled
You are submitting requests too quickly. Please retry your requests at a slower rate.

というエラーが出て値が取れない。
requests too quicklyとあるので時間をおいてアクセスしてもダメ!なんどやってもダメ!全然「too quickly」じゃ無いのに。

そもそも1日に多くても数回しかアクセスしていない(テストでも2桁前半)のに、「requests too quickly」なら、誰が使えんねん!と思いつつググる。

以下のポリシーの変更(特に売り上げ実績のところ)のせいなのかと思いアカウントを管理している部署に問い合わせるも、売り上げはあるとの回答(額は教えてくれない)
https://affiliate.amazon.co.jp/help/node/topic/GW65C7J2CSK7CA6C

2019年01月23日以降、過去30日以内のPA-API経由の売上実績(発送済み商品売上)がない場合、PA-APIへのアクセスができなくなる可能性がございます。

結局、理由がわからない。

ここで、ツールがループしてなんどもamazon PA-APIにアクセスしているのかと疑う。

スクラッチパッドでもデーターが取れない

v5.0用の認証情報 (AWSアクセスキーとAWSシークレットキー) でスクラッチパッドで書籍を検索してもデーターが取れない。

また、これでツールがループしてなんどもamazon PA-APIにアクセスしていないこが証明できた。

もうわけわからん。

amazonの担当者にメールで問い合わせ

送った内容

今週から、「Associate Tag:●●●●●●」アカウントでAPIを叩くと
「Error! RequestThrottled」とのエラーが出るようになりました。
「 You are submitting requests too quickly. Please retry your requests at a
slower rate.」とありますが、多くてもアクセスは1時間に数回です。

また、ネットで調べると、規約改定により、30日間、売り上げが無いとAPIが使えなくなり、その時も上記エラーが出る。とありました。
上記のエラーはこれに該当するものでしょうか?

また、ほかに原因となりそうな点がございましたらご教示いただけると幸いです。
よろしくお願い申し上げます。

amazonカスタマーサービスから返ってきたのは

Amazon.co.jpアソシエイト・プログラムにお問い合わせいただき、ありがとうございます。

下記メッセージが表示される状態はAPIのサーバーに複数の同時アクセスがあり、先着順で接続処理が行われ、その中で接続出来なかった方に表示されるものとなります。

---------------------------------------------------------------------
You are submitting requests too quickly. Please retry your requests at a
slower rate.
---------------------------------------------------------------------
つまり、お客様以外にも多数のお客様がPA-APIのリクエストを試みている場合は上記メッセージは出やすくなるかと存じます。

1日のリクエスト可能数をご理解の上、上記メッセージが返却・表示された場合は、再度リクエストを送信いただきますようお願いいたします。

アソシエイト・プログラムをご利用いただき、ありがとうございます。

この回答に対し、再度の返信

返信いただいた下記メッセージでは「お客様以外にも多数のお客様がPA-APIのリクエストを試みている場合は上記メッセージは出やすくなるかと存じます。」とありますが、これは我々だけでなく、その他の(世界中の)ユーザーも
含めてのことでしょうか。

今もAPIにアクセスを行いましたが、到達できませんでした。今週一度もAPIにアクセスできていません。
原因は、複数の同時アクセスが問題というだけでしょうか。
ご回答いただけると幸いです。よろしくお願い申し上げます。

amazonカスタマーサービスからの返答

カスタマーサービスからのお知らせ

Amazon.co.jpアソシエイト・プログラムにお問い合わせいただき、ありがとうございます。

下記メッセージが表示される状態はAPIのサーバーに複数の同時アクセスがあり、先着順で接続処理が行われ、その中で接続出来なかった方に表示されるものとなります。

---------------------------------------------------------------------
You are submitting requests too quickly. Please retry your requests at a
slower rate.
---------------------------------------------------------------------

つまり、お客様以外にも多数のお客様がPA-APIのリクエストを試みている場合は上記メッセージは出やすくなるかと存じます。

1日のリクエスト可能数をご理解の上、上記メッセージが返却・表示された場合は、再度リクエストを送信いただきますようお願いいたします。

要するに、世界中から同時にAPIにアクセスする数が単純に多いから、ということ???

諦めて、ツールを作り直す

もはや、APIから情報を取ることを諦め、該当の商品ページのHTMLからスクレイピングして必要なデーターを取ってこれるツールを作成することに決めました。

ツールを何で作ろうかと考えたのだが、Excel VBAにしました。

ググると、amazon PA-APIの問題は時間が解決してくれるとの情報がちらほらあったのと、
phpを使っているサーバーが古いということもあり、
会社のAWSにインスタンス立てて、そこでもよかったのですが、お金もかかるし申請が面倒なので、

どの環境でも動く「Excel VBA」で作りました。

基本設計

Dim isbn As String
Dim ans As String
Dim doc As New XmlScraping
isbn = InputBox("ISBN-10を入力ください", "")
ans = "https://www.amazon.co.jp/dp/" & isbn
If ans <> "" Then
   doc.gotoPage ans
End If

ユーザーにinputboxからISBN-10を入力してもらい、その値を、https://www.amazon.co.jp/dp/の文末に追加し、変数ansに格納。
gotoPageでそのページに移動し、データーを変数docに格納する。

後は、ワークシートの「tool」をターゲットに値を貼り付けていく

Worksheets("tool").Select
numberTitles = doc.css(".content ul li").count
Cells(1, 1) = "タイトル"
Cells(1, 2) = doc.css("#productTitle").index(0).text
Cells(2, 1) = "画像URL"
Cells(2, 2) = doc.css("#img-canvas").index(0).html
Cells(3, 1) = "価格"
Cells(3, 2) = doc.css(".a-color-price").index(0).text
Cells(3, 2) = Replace(Cells(3, 2), "¥", "")
Cells(3, 2) = Replace(Cells(3, 2), "\", "")
For i = 1 To numberTitles - 1
    If InStr(doc.css(".content ul li").index(i).text, "出版社") > 0 Then
        Cells(5, 2) = doc.css(".content ul li").index(i).text
        Cells(5, 2) = Replace(Cells(5, 2), "出版社: ", "")
        Cells(5, 1) = "出版社"
    ElseIf InStr(doc.css(".content ul li").index(i).text, "ISBN-10") > 0 Then
        Cells(6, 2) = doc.css(".content ul li").index(i).text
        Cells(6, 2).NumberFormatLocal = "@"
        Cells(6, 2) = Replace(Cells(6, 2), "ISBN-10: ", "")
        Cells(6, 1) = "amazonコード"
    End If
Next i

後は、正規表現で必要な値を取り出していく。例えば以下。

    Dim x As String
    Dim regx As RegExp
    Dim m As Match
    Dim ms As MatchCollection
    Set regx = New RegExp
    regx.Pattern = "https:\/\/images-.{2}\.ssl-images-amazon\.com\/images\/.*\.jpg"
    regx.Global = True
    Set ms = regx.Execute(Cells(2, 2))
    For Each m In ms
        Cells(2, 2) = m
    Next
    Set regx = Nothing
    Cells(2, 2) = Replace(Cells(2, 2), "https://images-fe.ssl-images-amazon.com/images/I/", "")

同じようにISBNを使って楽天の該当商品まで行き、値を取って正規表現で綺麗にしてあげればOK。

ans2 = "https://books.rakuten.co.jp/search?sitem=" & Cells(6, 2)
If ans2 <> "" Then
    doc2.gotoPage ans2
End If
Cells(7, 2) = doc2.css(".rbcomp__item-list__item__image").index(0).html
Dim x2 As String
Dim regx2 As RegExp
Dim m2 As Match
Dim ms2 As MatchCollection
Set regx2 = New RegExp
regx2.Pattern = "https:\/\/books\.rakuten\.co\.jp\/rb\/.{8}\/"
regx2.Global = True
Set ms2 = regx2.Execute(Cells(7, 2))
For Each m2 In ms2
Cells(7, 2) = m2
Next
Cells(7, 2) = Replace(Cells(7, 2), "https://books.rakuten.co.jp/", "")
Set regx2 = Nothing

ASINの場合は楽天の商品と紐付かない

商品コードがISBNの場合はそれをアマゾンにも楽天にも持っていいって使えるのだが、ASINの場合は紐付かない。
色々考えたんですが結局、ユーザーにASINJANを入力してもらう事にしました。

以上。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHP 正規表現

前提

PHPにおける正規表現について記述していきます。

本題

行頭にマッチする

^
#例:^hello。行頭にhelloの文字列はこのパターンにマッチする。

行末にマッチする

$
#例:hello$。行末にhelloの文字列はこのパターンにマッチする。

改行以外の任意の1文字にマッチする

.
#例:1、hello.world。hello worldやhello-worldなどの文字列はこのパターンにマッチする。 

英大文字A-Zの任意1文字にマッチする

[A-Z]
#例:1、a[A-Z]c。aAc,aBc,…,aZcなどの文字列はこのパターンにマッチする。 

英小文字a-zの任意1文字にマッチする

[a-z]
#例:1、a[a-z]c。aac,abc,…,azcなどの文字列はこのパターンにマッチする。

数字0-9の任意1文字にマッチする

[0-9]
#例:1、a[0-9]c。a0c,a1c,…,a9cなどの文字列はこのパターンにマッチする。

角括弧内に含まれない1文字にマッチする

[^]
#例:1、[^abc]。a、b、c以外の文字はこのパターンにマッチする。

直前の表現を0回以上繰り返す

*
#例:a、ab、abb、abbbなどはマッチする。

直前の表現を1回以上繰り返す

+
#例:ab、abb、abbbなどの文字列はこのパターンにマッチする。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelのルーティング基本

web.php

routes\web.php
ルーティングに関する情報の記載。

記入内容
・アドレス指定
・コントローラを指定
・コントローラのメソッドを指定

コントローラ

Http\Controllers\コントローラ名

php artisan make::controller コントローラ名

で作成する。
作成されたコントローラは、Http\Controllers\コントローラ名 に作成される。

useでrequrestやresponseやフォームリクエスト等のクラスをインポートし、メソッドの引数で読み込むことで利用可能にする。

return view('テンプレートフォルダ名', 渡す値);

この第1引数に読み込むテンプレートフォルダ名を記入。helloフォルダのindexファイルの場合は、hello.indexと記入する。
第2引数の値は、配列。この値をテンプレートに渡す。

Bladeテンプレート

resourdes\views\フォルダ名.blade.php

{{$変数名}}で、コントローラ等から渡された値を表示できる。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

[WIP] ヘルパ DI クラス一覧

以下は全ヘルパと実際のクラスまたは代替の一覧です。

配列とオブジェクト

helper class method
Arr::* Illuminate\Support\Arr *
data_fill Illuminate\Support\Arr add ※1
data_get Illuminate\Support\Arr get ※1
data_set Illuminate\Support\Arr set ※1
head Illuminate\Support\Arr first ※1
last Illuminate\Support\Arr end ※1

※1 代替。同じではない。

パス

helper class method
app_path Illuminate\Foundation\Application path
base_path Illuminate\Foundation\Application basePath
config_path Illuminate\Foundation\Application configPath
database_path Illuminate\Foundation\Application databasePath
mix Illuminate\Foundation\Mix そのまま呼ぶ(__invoke)
public_path Illuminate\Foundation\Application publicPath
resource_path Illuminate\Foundation\Application resourcePath
storage_path Illuminate\Foundation\Application storagePath

文字列

helper class method
__ Illuminate\Translation\Translator get
class_basename
e
preg_replace_array
Str::* Illuminate\Support\Str *
trans(引数なし) Illuminate\Translation\Translator
trans(引数あり) Illuminate\Translation\Translator get
trans_choice Illuminate\Translation\Translator choice

URL

helper class method
action Illuminate\Routing\UrlGenerator action
asset Illuminate\Routing\UrlGenerator asset
route Illuminate\Routing\UrlGenerator route
secure_asset Illuminate\Routing\UrlGenerator asset(第2引数に true を指定)
secure_url Illuminate\Routing\UrlGenerator to(第3引数に true を指定)
url(引数なし) Illuminate\Routing\UrlGenerator
url(引数あり) Illuminate\Routing\UrlGenerator to

その他

helper class method
abort Illuminate\Foundation\Application abort
abort_if Illuminate\Foundation\Application abort と if 文など
abort_unless Illuminate\Foundation\Application abort と if 文など
app(引数なし) Illuminate\Foundation\Application
app(引数あり) Illuminate\Foundation\Application make
auth(引数なし) Illuminate\Auth\AuthManager
auth(引数あり) Illuminate\Auth\AuthManager guard
back Illuminate\Routing\Redirector back
bcrypt Illuminate\Contracts\Hashing\Hasher driver('bcrypt')->make
blank
broadcast Illuminate\Contracts\Broadcasting\Factory event
cache(引数なし) Illuminate\Cache\CacheManager
cache(引数あり) Illuminate\Cache\CacheManager get または put
class_uses_recursive
collect Illuminate\Support\Collection make
config(引数なし) Illuminate\Config\Repository
config(引数あり) Illuminate\Config\Repository get または set
cookie(引数なし) Illuminate\Contracts\Cookie\Factory
cookie(引数あり) Illuminate\Contracts\Cookie\Factory make
csrf_field
csrf_token Illuminate\Session\SessionManager token
dd
decrypt Illuminate\Encryption\Encrypter decrypt
dispatch
dispatch_now Illuminate\Contracts\Bus\Dispatcher dispatchNow
dump
encrypt Illuminate\Encryption\Encrypter encrypt
env Illuminate\Support\Env get
event Illuminate\Events\Dispatcher dispatch
factory Illuminate\Database\Eloquent\Factory of
filled
info Illuminate\Log\LogManager info
logger(引数なし) Illuminate\Log\LogManager
logger(引数あり) Illuminate\Log\LogManager debug
method_field
now Illuminate\Support\DateFactory now
old Illuminate\Http\Request old
optional
policy Illuminate\Contracts\Auth\Access\Gate getPolicyFor
redirect(引数なし) Illuminate\Routing\Redirector
redirect(引数あり) Illuminate\Routing\Redirector to
report Illuminate\Contracts\Debug\ExceptionHandler report
request(引数なし) Illuminate\Http\Request
request(引数あり) Illuminate\Http\Request only またはプロパティアクセス (__get)
rescue
resolve Illuminate\Foundation\Application make
response(引数なし) Illuminate\Contracts\Routing\ResponseFactory
response(引数あり) Illuminate\Contracts\Routing\ResponseFactory make
retry
session(引数なし) Illuminate\Session\SessionManager
session(引数あり) Illuminate\Session\SessionManager get または put
tap
throw_if
throw_unless
today Illuminate\Support\DateFactory today
trait_uses_recursive
transform
validator(引数なし) Illuminate\Contracts\Validation\Factory
validator(引数あり) Illuminate\Contracts\Validation\Factory make
value
view(引数なし) Illuminate\Contracts\View\Factory
view(引数あり) Illuminate\Contracts\View\Factory make
with
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

laravelで、LoginController.phpがない

php artisan make:model auth
を実行し、成功したのに、

ディレクトリ app/Http/Auth の中に、LoginController.phpのファイルがありません。
ctrl+Hを押下しましたが、表示されません。
なぜでしょうか。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelでビュー描画前処理を行う

Laravelのビュー描画前処理

Laravelのビュー描画前処理について書いていきます
Laravelではビューが描画される時に呼び出される処理を作成しておくことができます

前提条件

下記前回記事の続きです
Laravelのレイアウトエンジンを使う
本記事は上記が完了している前提で書かれています
上記記事で使用したプロジェクトを引き続き使用していきます

Controllerにメソッド追加

(1) /sample/app/Http/Controllers/SampleController.phpにviewComposeメソッドを追記
public function viewCompose()
{
$data = ['key' => 123456789.123456];
return view('sample.viewCompose', $data);
}

(2) /sample/routes/web.phpに下記を追記
Route::get('sample/view-compose', 'SampleController@viewCompose');

viewの作成

/sample/resources/views/sample/viewCompose.blade.phpファイル作成

viewCompose.blade.php
<html>
    <head>
        <title>sample</title>
    </head>
    <body>
        {{$key}}
    </body>
</html>

描画前処理の作成

(1) /sample/app/Http/ViewComposersフォルダ作成
(2) /sample/app/Http/ViewComposers/SampleComposer.phpファイル作成

SampleComposer.php
<?php

namespace App\Http\ViewComposers;

use Illuminate\View\View;

class SampleComposer {

    public function compose(View $view)
    {
        $view->with('key', number_format($view->getData()['key'], 2, '.', ','));
    }
}

描画前処理が呼び出されるように登録する

(1) /sample/app/Providers/ViewComposerServiceProvider.phpファイル作成

ViewComposerServiceProvider.php
<?php
namespace App\Providers;

use Illuminate\Support\Facades\View;
use Illuminate\Support\ServiceProvider;

class ViewComposerServiceProvider extends ServiceProvider{

    public function boot()
    {
        View::composer(
            'sample.viewCompose', 'App\Http\ViewComposers\SampleComposer'
        );

    }

    public function register()
    {
    }
}

(2) /sample/config/app.php内のproviders配列に下記を追記

ViewComposerServiceProvider.php
‥‥

'providers' => [

‥‥

App\Providers\ViewComposerServiceProvider::class,
],

‥‥

これでレンダリングの際に
ViewComposerServiceProvider#boot→View::composer→SampleComposer#compose
が実行されます

動作確認

http://localhost/laravelSample/sample/view-compose

実行結果

123,456,789.12
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

ブラックボックスの罠 Guzzlehttpで解決しなかった文字化けが、cURLにしたらサクッと解決した

はじめに

APIを使う側の場合、サンプルコードなどがあれば、まずはそれに忠実な操作、処理をして疎通を確認する。

ライブラリは便利だが、ブラックボックスになる面もあるのでトラブルの原因把握や問題解決から遠くなる危険がある。
ソースが公開されているのなら、それを辿るがよろし。

何が起こったか?

某決済業者のAPIを使い銀行振込用のバーチャル口座のリクエストを送った時に、全角文字が含まれているとその部分だけ文字化けが発生した。
なお、クレジットカード払いなどの別手段では発生しなかった。

参考:当方サーバ側環境

  • PHP7.X系
  • Laravel5.X系
  • guzzlehttp6.5.2
  • システム内のデフォルトの文字コードはUTF-8

PHPやLaravelそのものは関係なくて、guzzleの中の問題(断言)

問題調査で発生したこと

途方に暮れる

文字コードをSJISに変換する必要がある
→変換しても、文字化けた後の内容が変わっただけで根本的な解決にはならなかった。

リクエストを送るときのContent-Typeが問題 
→ Postmanなどの、API送信ツールを使ったが、文字化けしていた。

そのほか、URLエンコードした値を送信など様々な事を試みたがダメだった。

なお、業者がサンプルで提供している(本案件では採用しない)決済モジュールを動かしてみたら無事文字化けしなかった。

cURLで実装してみたら、問題なく送信できた!

決済モジュールのコードを辿ってみたら、全角文字列はSJISに変換する。
curl_setoptで、様々な設定をしたのちリクエストを送信。

結局、いかにもありそうなcURLのサンプルコードを書いて動かしたら成功した。

cURLでリクエストを送る
//前提:こんな感じのリクエスト値が存在する(実運用時には、他のメソッドで加工するケースが多いと思います)

$params = [
    'access_code' => 'unique_access_code',
    'price' => '3980',
    'customer_name' => mb_convert_encoding('バカ殿様','SJIS','UTF-8')
];

//POSTする値を
$post_fields = http_build_query($params);

// APIのリクエスト先URL。各自の環境に置き換えて考えてください
$request_url = "https://example.com/path/to/api/receiver";


//まず、オブジェクトを作る
$curl = curl_init();

//リクエスト形式、戻り値の存在、リクエスト先などを設定する。
//URLは適宜考えてください

curl_setopt($curl,CURLOPT_URL,$request_url);
curl_setopt($curl,CURLOPT_POST,true);
curl_setopt($curl,CURLOPT_RETURNNUMBER,true);

//リクエスト先の仕様にそろえて、URLエンコード済の値をセットする
curl_setopt($curl,CURLOPT_POSTFIELDS,$post_fields);

//ここから下、cURLのリクエスト送信とレスポンス

$response = curl_exec( $curl );
$curlinfo = curl_getinfo( $curl );
curl_close( $curl );




顧客名は、時事ネタです(合掌)

犯人は(たぶん)お前だ!

guzzlehttp/guzzle/src/Client.php

applyOptionsメソッド内にてhttp_build_queryを使っていたが
ここでクエリを編集する部分に問題があるようだ。

guzzlehttp/guzzle/src/Client.php
//
        if (isset($options['query'])) {
            $value = $options['query'];
            if (is_array($value)) {
                $value = http_build_query($value, null, '&', PHP_QUERY_RFC3986);//この行に問題あり
            }
            if (!is_string($value)) {
                throw new \InvalidArgumentException('query must be a string or array');
            }
            $modify['query'] = $value;
            unset($options['query']);
        }



PHPリファレンスのhttp_build_queryのページによれば 4つ目の引数enc_typeは

デフォルトでは PHP_QUERY_RFC1738つまり、RFC1738 に従ってエンコードされる。でよかったにも関わらず 上記ソースの抜粋のようにPHP_QUERY_RFC3986でエンコードされていた…これが原因のようだ。

参考

PHP:http_build_query

https://www.php.net/manual/ja/function.http-build-query.php

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelのレイアウトエンジンを使う

Laravelのレイアウト処理

Laravelのレイアウト処理について書いていきます
viewsフォルダ配下に作成したblade.phpファイルを組み合わせて1つのビューとして処理をするものです

前提条件

下記前回記事の続きです
Laravelのテンプレートエンジンを使う
本記事は上記が完了している前提で書かれています
上記記事で使用したプロジェクトを引き続き使用していきます

Controllerにメソッド追加

(1) /sample/app/Http/Controllers/SampleController.phpにchildメソッドを追記
public function child()
{
$data = ['msgList' => ["msg1", "msg2"]];
return view('sample.child', $data);
}

(2) /sample/routes/web.phpに下記を追記
Route::get('sample/child', 'SampleController@child');

viewの作成

(1) /sample/resources/views/layoutフォルダ作成
(2) /sample/resources/views/layout/parent.blade.phpファイル作成

parent.blade.php
<html>
    <head>
        <title>@yield('title')</title>
    </head>
    <body>
        <ul>
            @section('menu')
            <li>共通メニュー1</li>
            <li>共通メニュー2</li>
            @show
        </ul>
        <div>
            @yield('content')
        </div>
    </body>
</html>

(3) /sample/resources/views/componentフォルダ作成
(4) /sample/resources/views/component/msgList.blade.phpファイル作成

msgList.blade.php
<div>{{ $msgTitle }}</div>
@foreach ($msgList as $msg)
    <div>{{ $msg }}</div>
@endforeach
{{ $addMsg }}

(5) /sample/resources/views/sample/child.blade.phpファイル作成

child.blade.php
{{-- resources/views/layout/parent.blade.phpを使うのでlayout.parentにする --}}
@extends('layout.parent')

{{-- parent.blade.phpの@yield('title')を置換する --}}
@section('title', 'Sample@tpl')

{{-- parent.blade.phpの@section('menu')から@showまでを置換する --}}
@section('menu')
    {{-- parent.blade.phpの@section('menu')から@showまでを描画する --}}
    @parent
    {{-- child.blade.php独自のメニューを描画する --}}
    <li>独自メニュー1</li>
    <li>独自メニュー2</li>
@endsection

{{-- parent.blade.phpの@yield('content')を置換する --}}
@section('content')
    <p>child.blade.phpのコンテンツ</p>

    {{-- resources/views/component/msgList.blade.phpを描画する --}}
    @component('component.msgList', ['msgTitle' => 'コンポーネントタイトル', 'msgList' => $msgList])
        @slot('addMsg')
            <div>addMsg1</div>
            <div>addMsg2</div>
        @endslot
    @endcomponent

    {{-- resources/views/component/msgList.blade.phpを描画する --}}
    @include('component.msgList', ['msgTitle' => 'インクルードタイトル', 'msgList' => $msgList, 'addMsg' => '<div>addMsg1</div><div>addMsg2</div>'])

@endsection

動作確認

http://localhost/laravelSample/sample/tpl

実行結果

● 共通メニュー1
● 共通メニュー2
● 独自メニュー1
● 独自メニュー2

child.blade.phpのコンテンツ

コンポーネントタイトル
msg1
msg2
addMsg1
addMsg2
インクルードタイトル
msg1
msg2
<div>addMsg1</div><div>addMsg2</div>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravelのテンプレートエンジンを使う

Laravelの描画処理

Laravelの描画処理を行うbladeテンプレートエンジンの使い方を書いていきます
@と様々な予約語を組み合わせることでいろいろな描画処理をすることができます

前提条件

下記前回記事の続きです
eclipseでLaravel開発環境を構築する。デバッグでブレークポイントをつけて止める。(WindowsもVagrantもdockerも)
本記事は上記が完了している前提で書かれています
プロジェクトの作成もapacheの設定も上記で行っています

Controllerにメソッド追加

  1. /sample/app/Http/Controllers/SampleController.phpにtplメソッドを追記
    public function tpl()
    {
    $data = ['val' => 2,
    'parentList' => ['key1' => 1],
    'list' => ['key1' => 1, 'key2' => 2, 'key3' => 3],
    'emptyList' => []
    ];
    return view('sample.tpl', $data);
    }

  2. /sample/routes/web.phpに下記を追記
    Route::get('sample/tpl', 'SampleController@tpl');

viewの作成

  1. /sample/resources/views/sample/tpl.blade.phpファイル作成
tpl.blade.php
<html>
    <head>
        <title>sample</title>
    </head>
    <body>

        {{-- コメント --}}

        {{-- {!!  !!}はエスケープしないデータの表示 --}}
        <div>[{!! '&#064;php' !!}]</div>
        @php
            $tplVal = 10;
            echo '<div>' . $tplVal . '</div>';
        @endphp

        <br>

        <div>[echo]</div>
        <div>{{ $val }}</div>
        <br>

        <div>[if]</div>
        @if ($val === 1)
            <div>1</div>
        @elseif ($val === 2)
            <div>2</div>
        @else
            <div>else</div>
        @endif
        <br>

        <div>[switch]</div>
        @switch($val)
            @case(1)
                <div>1</div>
                @break
            @case(2)
                <div>2</div>
                @break
            @default
                <div>default</div>
        @endswitch
        <br>

        <div>[unless]</div>
        @unless (true)
            <div>true</div>
        @else
            <div>false</div>
        @endunless
        <br>

        <div>[isset]</div>
        @isset($list['key1'])
            <div>isset true</div>
        @else
            <div>isset false</div>
        @endisset
        <br>

        <div>[empty]</div>
        @empty($list['key1'])
            <div>empty true</div>
        @else
            <div>empty false</div>
        @endempty
        <br>

        <div>[for]</div>
        @for ($i = 0; $i < 10; $i++)
            @if ($i == 1)
                @continue
            @endif
            <div>{{ $i }}</div>
            @if ($i >= 3)
                @break
            @endif
        @endfor
        <br>

        <div>[foreach]</div>
        @foreach ($list as $listKey => $listVal)
            @if ($listVal == 1)
                @continue
            @endif
            <div>{{ $listKey }}:{{ $listVal }}</div>
            @if ($listVal >= 3)
                @break
            @endif
        @endforeach
        <br>

        <div>[forelse]</div>
        @forelse ($emptyList as $listKey => $listVal)
            <div>{{ $listKey }}:{{ $listVal }}</div>
        @empty
            <div>空っぽのリストです</div>
        @endforelse
        <br>

        <div>[while]</div>
        @php
            $whileIndex = 0;
        @endphp
        @while ($whileIndex <= 3)
            <div>{{ $whileIndex }}</div>
            @php
                $whileIndex++;
            @endphp
        @endwhile
        <br>

        <div>[$loop]</div>
        @foreach ($parentList as $parentListKey => $parentListVal)
            <div>parent:{{ $parentListKey }}:{{ $parentListVal }}</div>
            @foreach ($list as $listKey => $listVal)
                <div>child:{{ $listKey }}:{{ $listVal }}</div>
                <div>$loop->index:    {{ $loop->index }}</div>
                <div>$loop->iteration:{{ $loop->iteration }}</div>
                <div>$loop->remaining:{{ $loop->remaining }}</div>
                <div>$loop->count:    {{ $loop->count }}</div>
                <div>$loop->first:    {{ $loop->first }}</div>
                <div>$loop->last:     {{ $loop->last }}</div>
                <div>$loop->even:     {{ $loop->even }}</div>
                <div>$loop->odd:      {{ $loop->odd }}</div>
                <div>$loop->depth:    {{ $loop->depth }}</div>

                <div>$loop->parent->index:    {{ $loop->parent->index }}</div>
                <div>$loop->parent->iteration:{{ $loop->parent->iteration }}</div>
                <div>$loop->parent->remaining:{{ $loop->parent->remaining }}</div>
                <div>$loop->parent->count:    {{ $loop->parent->count }}</div>
                <div>$loop->parent->first:    {{ $loop->parent->first }}</div>
                <div>$loop->parent->last:     {{ $loop->parent->last }}</div>
                <div>$loop->parent->even:     {{ $loop->parent->even }}</div>
                <div>$loop->parent->odd:      {{ $loop->parent->odd }}</div>
                <div>$loop->parent->depth:    {{ $loop->parent->depth }}</div>

                @if ($listVal >= 2)
                    @break
                @endif

            @endforeach
        @endforeach
        <br>

    </body>
</html>

動作確認

http://localhost/laravelSample/sample/tpl

実行結果

[@php]
10

[echo]
2

[if]
2

[switch]
2

[unless]
false

[isset]
isset true

[empty]
empty false

[for]
0
2
3

[foreach]
key2:2
key3:3

[forelse]
空っぽのリストです

[while]
0
1
2
3

[$loop]
parent:key1:1
child:key1:1
$loop->index: 0
$loop->iteration:1
$loop->remaining:2
$loop->count: 3
$loop->first: 1
$loop->last:
$loop->even:
$loop->odd: 1
$loop->depth: 2
$loop->parent->index: 0
$loop->parent->iteration:1
$loop->parent->remaining:0
$loop->parent->count: 1
$loop->parent->first: 1
$loop->parent->last: 1
$loop->parent->even:
$loop->parent->odd: 1
$loop->parent->depth: 1
child:key2:2
$loop->index: 1
$loop->iteration:2
$loop->remaining:1
$loop->count: 3
$loop->first:
$loop->last:
$loop->even: 1
$loop->odd:
$loop->depth: 2
$loop->parent->index: 0
$loop->parent->iteration:1
$loop->parent->remaining:0
$loop->parent->count: 1
$loop->parent->first: 1
$loop->parent->last: 1
$loop->parent->even:
$loop->parent->odd: 1
$loop->parent->depth: 1

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel Dump Server インストールエラー Argument 1 passed to Symfony\Component\VarDumper\Server\Connection::__construct() must be of the type string

https://github.com/beyondcode/laravel-dump-server Laravel Dump Serverのライブラリをインストールしようとしたところ謎のエラーが発生してしまいました。

環境

  • PHP 7.4.5
  • Laravel 7.5.1
  • Laravel Dump Server 2.7.0

問題

$ composer require --dev beyondcode/laravel-dump-server

Using version ^1.4 for beyondcode/laravel-dump-server
./composer.json has been updated
Loading composer repositories with package information
Updating dependencies (including require-dev)
Nothing to install or update
Package zendframework/zend-code is abandoned, you should avoid using it. Use laminas/laminas-code instead.
Package zendframework/zend-eventmanager is abandoned, you should avoid using it. Use laminas/laminas-eventmanager instead.
Generating optimized autoload files
> Illuminate\Foundation\ComposerScripts::postAutoloadDump
> @php artisan package:discover --ansi

In Connection.php line 32:

  Argument 1 passed to Symfony\Component\VarDumper\Server\Connection::__const  
  ruct() must be of the type string, null given, called in /work/backend/vend  
  or/beyondcode/laravel-dump-server/src/DumpServerServiceProvider.php on line  
   49                                                                          


Script @php artisan package:discover --ansi handling the post-autoload-dump event returned with error code 1

Installation failed, reverting ./composer.json to its original content.

インストールに失敗してちょっとビビリました。

対策

https://github.com/beyondcode/laravel-dump-server/issues/48

こちらのイシューを見たところ、キャッシュが悪さしてるようです。

$ rm bootstrap/cache/config.php

キャッシュファイルを削除して、再度インストールしなおせばokです。

$ composer require --dev beyondcode/laravel-dump-server
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

CodeIgniter4でDB接続まで

インストール〜環境設定まではこちらをご覧ください。

DB接続テストの前にコントローラについてかんたんに説明

あなたのホストはhttp://exapmle.com/だと仮定します。

まずは、ブラウザでCI4のトップページが見えている状態にしてください。
そして、現在はci4tsetのディレクトリ内にいると仮定します。

ディレクトリの構成(今回出てくるファイルのみ表示)
/home/ci4test
├── .env                        <-- 前回作った環境設定ファイル
├── app
│   └── Controllers
│       └── Home.php            <-- 今回操作するファイル
├── htdocs                      <-- 前回書き換えたドキュメントルート
│   └── index.php
└── writable

このページはapp/Controllers/Home.phpのコントローラで動いています。
CI4ではControllerディレクトリ配下の(拡張子を除いた)ファイル名=クラス名=URLのパスの第一階層というルールで動作しています。

URLはどうなっているのか?

apacheでmod_rewriteが有効ならば、htdocs/.htaccessが適切にURLの書き換えを行ってくれます。
この場合は、
http://example.com/コントローラのクラス名/メソッド名/[引数1/[引数2/]...]
という形でアクセスできます。無効の場合は
http://example.com/index.php/コントローラのクラス名/メソッド名/[引数1/[引数2/]...]
という形になります。
この辺はCI3の仕組みがそのまま踏襲されています。

なぜトップページがHome.phpなのか?

これはapp/Config/Routes.phpHome.phpHomeクラスのindexというメソッド(関数)が/だぞという定義が記述してあるからなのですが、この辺は今回は割愛します。
(ここらへんのRoutingの仕組みはCI3とほぼ同じです)

そしてCIのルーティングに不慣れな人は面食らうかもしれませんが、現在の設定において
http://exapmle.com/ (クラス名、メソッド名が省略)

http://exapmle.com/Home (メソッド名が省略)
であり
http://exapmle.com/Home/index (両方ちゃんと表記したもの)
でもあり、これはすべて同じページを指します。

この辺のURLの記述ルールは頭に入れておいたほうがいいと思います。

接続テスト

いよいよDBに接続するテストをしてみます。

まずapp/Controllers/Home.phpのコントローラをエディタで開いてください。
ファイルのソースは次のような感じになっているはずです。

app/Controllers/Home.php
<?php namespace App\Controllers;

class Home extends BaseController
{
    public function index()
    {
        return view('welcome_message');
    }

    //--------------------------------------------------------------------

}

ここに次のメソッドを追加してください。

app/Controllers/Home.php
<?php namespace App\Controllers;

use Config\Database;

class Home extends BaseController
{
    public function index()
    {
        return view('welcome_message');
    }

    //--------------------------------------------------------------------

    public function connectionTest()
    {
        $db = Database::connect();
        echo "このDBのテーブル=" . implode( ',' , $db->listTables() );
        return;
    }
}

動作をチェックするにはhttp://example.com/Home/connectionTest/にアクセスしてください。
すでにDBが存在し、何がしかのテーブルがあれば、そのDBのすべてのテーブル名がカンマ区切りで表示されます。
テーブルがない場合はこのDBのテーブル=のみが表示されるはずです。
もしDBが存在しない場合は、DBドライバがSQLite3以外の場合はエラー画面が表示されます。

話が少しそれますが、SQLite3の場合、DBが存在しないときは.envファイルのdatabase.default.databaseで設定された名前のSQLite3のDBファイルが作られます。このパラメータはのパスを省略した場合ドキュメントルート直下にDBファイルが生成されます。
なお、このディレクトリが書込み可能でない場合はエラーになります。
このファイル名はもちろん絶対パスや、ドキュメントルートを起点とした../writable/ci4test.dbのような相対パスで記述も可能です。

照合順序も設定可能です

MySQLで文字コードや照合順序を指定する場合は、.env

.env
 database.default.charset = utf8mb4 あるいは utf8 など Collationに合わせた文字コード
 database.default.DBCollat = utf8mb4_general_ci や utf8_general_ci などお好みの照合順序

を記述することで指定した文字コード及び照合順序で接続が可能になります。

次回はDBForgeを利用してDB自体を作る方法を解説したいと思います。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

PHPでのMySQL (データベース)接続 PDO

PDOとは

PHP Data Objectsrの略称
PHPからデータベースのアクセスを抽象的にしてくれるもの

PHPからMySQLに接続するコード例(SELECT文)

<?php

$mysql    = 'mysql:host=localhost;dbname=xxxxxx,charet=utf8';
//xxxxxx === 自分のmysql中の接続したいデータベース名
$user     = 'xxxxxx'; 
//xxxxxx === 自分のmysqlユーザー名
$passwoad = 'xxxxxx'; 
//xxxxxx === 自分のmysqlパスワード

try {
    $db     = new PDO($mysql, $user, $passwoad);
    $select = "SELECT * FROM" ;
    $res    = $db->query($select);

} catch (PDOException $e) {
    echo '接続エラー: ' . $e->getMessage();
}

?>
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

注意!あなたのWordPressも狙われている!?侵入手口と挙動について

皆さんが当たり前のように使っているWordPressには,実は脅威が存在します。
乗っ取られると素人ではなかなか解析できないような複雑な改ざんが行われて,復元しないとページが見られなくなります。
今回はそのハッキングの一例を取り上げます。
「こっちはセキュリティ対策してるから大丈夫」ってわけにはいかないみたいですよ...

まえがき

該当する事例が前にあったようです。
https://qiita.com/mikkame/items/eec33df6863ed81740c2

侵入経路

不明。
どこから入ってきたのかは分かりませんが,恐らくテーマやプラグインを脆弱性を突きXSSを利用してPHPコードを実行させて環境を整えたと見られます。

挙動

この例としては

  • /wp-load.php
  • /wp-blog-header.php
  • /index.php
  • /wp-content/themes/twentyfifteen/inc/index.php
  • /wp-content/themes/calliope/inc/index.php

が不正に書き換えられました。

何をされた?

/index.phpには,偽のサイトマップをGoogleなどに返す機能,ハッカー側がハッキングを完了したことを確認するために自らをGoogle検索してハッキングされているかを確かめる機能,botには普通のサイトのように見せかける機能などが追加されます。

一番危ないのが Twenty Fifteenのindex.phpです。
こちらをご覧ください。
image.png
なんと,ハッカーが使う隠しファイルマネージャーが用意されていたのです。
このファイルマネージャーはやけに高機能で,パーミッションの変更,ファイルのアップロード,さらにはローカルコンピューターへのアクセスも可能になっています。
これは非常に危ない脆弱性であり,WordPressを使っている皆さんは注意が必要です。

侵入されないようにやっておくこと

まず大事なのは WordPressのアップデート です。
プラグインは定期的に更新する,評判の良くないものは使わない,テーマも定期的に更新する,そしてなにより,WordPressのシステムを最新に保つことが必要と言えます。

おわりに

何かこの事に関して知っていることがあれば,ご教授ください。

  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

raspberrypiとESP32を使った自分でIoTプラットホーム作成(その2)~ESP32設定編Lチカ

ESP32の設定

家に転がっていたESP32の動作確認をしました。
Arduino-IDE ver1.8.10を使ってESP32ボードを認識させて下記コードを実行します。
LEDが点滅したら成功です。LEDの+と接続するpinの場所は任意です。

ちなみにLEDが壊れていて2回目で成功しました。

void setup() {
  // put your setup code here, to run once:
  pinMode(33,OUTPUT);
}

void loop() {
  // put your main code here, to run repeatedly:
  digitalWrite(33,HIGH);
  delay(500);
  digitalWrite(33,LOW);
  delay(500);
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel バリデーションを設定する ~コントローラ編~

目的

  • 入力値をDBに保存する際にアプリケーション側でそのデータが要件を満たしているのかをフィルターする仕組みを実装する

実施環境

  • ハードウェア環境
項目 情報
OS macOS Catalina(10.15.3)
ハードウェア MacBook Pro (16-inch ,2019)
プロセッサ 2.6 GHz 6コアIntel Core i7
メモリ 16 GB 2667 MHz DDR4
グラフィックス AMD Radeon Pro 5300M 4 GB Intel UHD Graphics 630 1536 MB
  • ソフトウェア環境
項目 情報 備考
PHP バージョン 7.4.3 Homwbrewを用いて導入
Laravel バージョン 7.0.8 commposerを用いて導入
MySQLバージョン 8.0.19 for osx10.13 on x86_64 Homwbrewを用いて導入

説明に関する前提の説明

  • 下記の方法、またはそれに準ずる方法でLaravelの環境を構築していること。
  • Laravelのアプリケーションが存在すること。

説明に関する前提のコード

  • 下記のような「ビューでの入力値をDBに格納する処理」が存在する事を前提として説明を行う。
  1. ルーティングファイル

    web.php
    //入力フォームを表示する
    Route::get('/new', 'ContentController@new');
    //入力値を受け取ってDBに保存する
    Route::post('/create', 'ContentController@create');
    
  2. コントローラファイル(当該アクション部分のみ記載する)

    ContentController.php
    //入力フォームを表示する contentディレクトリのnew.blade.phpを表示する
    public function new() {
        return view('content.new');
    }
    
    //入力値を受け取ってDBに保存する DBへの格納処理の記載は省略する
    public function create(Request $request) {
    
        //受け取った値を連想配列に格納
        $notice_info = $request->all();
    
        //DBへの登録処理
    }
    
  3. ビューファイル

    content/new.blade.php
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Document</title>
    </head>
    <body>
      <form action="/create" method="POST">
        <input type="text" name="input_content">
        <input type="submit" value="送信">
      </form>
    </body>
    </html>
    

実施方法概要

  • コントローラにバリデーションを記載する方法をまとめる。
  1. バリデーションルールの設定
  2. バリデーション本体の記載
  3. 確認

実施方法詳細

  1. バリデーションルールの設定

    1. 下記のようにコントローラに記載してバリデーションルールを定義する。
    2. バリデーション内容は「空状態での送信をブロックする」ものとする
    3. バリデーションルールに引っかかった場合、/newのページ(入力を行って送信ボタンをクリックしたページ)にリダイレクトされるようにする。

      ContentController.php
      //入力フォームを表示する contentディレクトリのnew.blade.phpを表示する
      public function new() {
          return view('content.new');
      }
      
      //入力値を受け取ってDBに保存する DBへの格納処理の記載は省略する
      public function create(Request $request) {
          //バリデーションのルール設定
          $rules = [
              //'ビューのinput要素のnameで指定したキーの名前' => ['バリデーションのルール'],のように記載する、requiredは空の状態での送信をブロックするルールである
              'input_content' => ['required'],
          ];
      
          //受け取った値を連想配列に格納
          $notice_info = $request->all();
      
          //DBへの登録処理
      }
      
  2. バリデーション本体の記載

    1. バリデーションの命令を記載する

      ContentController.php
      //入力フォームを表示する contentディレクトリのnew.blade.phpを表示する
      public function new() {
          return view('content.new');
      }
      
      //入力値を受け取ってDBに保存する DBへの格納処理の記載は省略する
      public function create(Request $request) {
          //バリデーションのルール設定
          $rules = [
              //'ビューのinput要素のnameで指定したキーの名前' => ['バリデーションのルール'],のように記載する、requiredは空の状態での送信をブロックするルールである
              'input_content' => ['required'],
          ];
      
          //下記のように記載してバリデーションを設定する
          //$this->validate(ビューのform要素から送られた値が格納された変数$request, バリデーションルールが格納された変数$rules);のように記載する
          $this->validate($request, $rules);
      
          //受け取った値を連想配列に格納
          $notice_info = $request->all();
      
          //DBへの登録処理
      }
      
    2. ビューファイルを編集してエラーメッセージを出力する記載を追加する。

    content/new.blade.php
    <!DOCTYPE html>
    <html lang="en">
    <head>
      <meta charset="UTF-8">
      <meta name="viewport" content="width=device-width, initial-scale=1.0">
      <meta http-equiv="X-UA-Compatible" content="ie=edge">
      <title>Document</title>
    </head>
    <body>
      <form action="/create" method="POST">
        <!-- 下記を追記する -->
        <!-- バリデーションルールはひとつであるが、複数のエラーメッセージが出力される事を想定してforeach文でエラーを出力する -->
        <!-- 配列$errorsのキー'input_content'にメッセージが格納されているかの分岐 -->
        @if ($errors->has('input_content'))
          <!-- 配列$errorsのキー'input_content'に格納されているメッセージを行っこづつ変数$input_content_errorに格納する -->
          @foreach ($errors->get('input_content') as $input_content_error)
            <!-- 変数$input_content_errorを出力する -->
            <p>{{$input_content_errors}}</p>
            <br>
          @endforeach
        @endif
        <!-- ひとつのエラーメッセージのみ出力したい場合、下記の記載でも可 -->
        <!--
        @if ($errors->has('input_content'))
          <p>{{$errors->first('input_content')}}</p>
        @endif
        -->
        <!-- 上記までを追記する -->
        <input type="text" name="input_content">
        <input type="submit" value="送信">
      </form>
    </body>
    </html>
    
  3. 確認

    1. /newにアクセスし、input要素で表示されている入力ボックスに何も入力せず「送信」ボタンをクリックする。
    2. /newが際表示される事を確認する。
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

【Laravel】Laravel DB設定

①MAMPを起動

アプリケーションからMAMPを開き、「サーバを起動」を押下する。

②phpMyAdminにアクセス

phpMyAdminにアクセスする。

③データベース作成

▪︎新規作成
左側のメニューから「新規作成」を押下する。

▪︎データベース名入力
フォームに作成したいデータベース名を入力する。

▪︎文字コード設定
プルダウンから文字コード「utf8_general_ci」を選択する。

▪︎作成
「作成」ボタンを押下する。

④特権の設定

▪︎データベースの選択
左側のメニューから特権を設定したいデータベースを選択する。
今回は先ほど③で作成したデータベースを選択する。

▪︎特権タブを開く
上部から「特権タブ」を開く。

▪︎ユーザアカウント追加
「ユーザアカウントを追加する」を押下する。

▪︎ログイン情報フォーム入力
ユーザ名、パスワード、再入力を入力する。
他の設定は変えない。

▪︎ユーザアカウント専用データベース設定
チェックボックスから「データベース laravel_task への全ての特権を与える。」を選択し、チェックを入れる。

▪︎グローバル特権設定
チェックボックスから「すべてチェックする」を選択し、チェックを入れる。

▪︎SSL設定
ラジオボタンから「REQUIRE NONE」を選択しする。

▪︎実行
「実行」ボタンを押下する。

⑤.envファイルのデータベース設定

.envファイルを開き、下記の通りデータベースを設定する。

公文)
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=8889
DB_DATABASE=【③で作成したデータベース名】
DB_USERNAME=【④で作成したユーザ名】
DB_PASSWORD=【④で設定したパスワード】
DB_SOCKET=/Applications/MAMP/tmp/mysql/mysql.sock

例)
DB_CONNECTION=mysql
DB_HOST=127.0.0.1
DB_PORT=8889
DB_DATABASE=laravel_task
DB_USERNAME=laravel_user
DB_PASSWORD=password123
DB_SOCKET=/Applications/MAMP/tmp/mysql/mysql.sock

⑥DBマイグレート

▪︎ディレクトリ移動

公文)
$ cd /Applications/MAMP/htdocs/プロジェクト名
例)
$ cd /Applications/MAMP/htdocs/laravel_test

▪︎DBマイグレート

$ php artisan migrate
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む