- 投稿日:2020-02-19T21:30:06+09:00
本格的なTwitterクローンを作る
Twitterのクローンアプリを10日間で作った話
今回、Web上で「CloudDiary」という交流サイトを作りました。
デモは以下をご覧ください。このアプリについて
主な機能はTwitterに似ており、デザインはGoogleが推奨するマテリアルUIを採用しました。言語はHTML,CSS,JavaScript,PHP,Ajax(非同期でいいね)です。メインページはSPAで、フッターのナビゲーションで画面遷移しても、ページバックした際は、前のページに戻ります。
機能一覧
- ログイン/ログアウト
- パスワードの不可逆暗号化(解読不可能な暗号としてDBに登録)
- 文章投稿
- 画像投稿
- いいね(Ajaxで非同期処理)
- コメント機能
- Twitter共有
- フォロー/フォロワー
- アイコン画像
- プロフィール変更
主な機能の仕組み
データベースは、usersテーブル,postsテーブル,likesテーブル,repliesテーブル,followsテーブルの5つから成り立っております。例えば何か投稿したら、usersテーブルのpost数が更新され、postsテーブルに詳細カラムが追加されます。このようにデータベースが連携し合っています。
PHP
基礎土台はこんな感じです。これを応用すれば、ユーザーごとのいいね数,コメント内容等を取り出して表示できます。
index.php<!--postsテーブルのnameを取り出す--> <?= foreach($posts as $row): ?> <?= echo $row['name']; ?> <?= endforeach; ?> <!--セッションがあればユーザーの名前を表示--> <?= if(isset($_SESSION['user'])): ?> <div class= "user-name"><?php echo $_SESSION['user']['name']; ?></div> <?= else: ?> <div class= "user-name">User name</div> <?= endif; ?>Ajax
いいねボタンが押された場合、Ajaxで非同期でlikesテーブルに新情報を挿入します。メリットとしては、例えば下にスクロールしている際にいいねボタンを押した場合、ページがリロードされてトップに戻ることがなくなります。また、感覚としては瞬時にいいねボタンを押せるため、UXが向上します。
JavaScript
特定のボタンが押されたら、ポップアップ表示を出したり、部品をクリックしたときに波紋を出したりしています。
おわりに
今回はPHPを使ってこのような交流サイトを作ってみました。
何かアドバイス等あれば教えていただければと思います。
そして、この記事が皆様にお役に立てれば幸いです。
- 投稿日:2020-02-19T19:52:23+09:00
天気予報を取得するアレを使用してみた(Openweathermap_api)。
天気予報を取得するアレを使用してみた(Openweathermap_api)。
ご自由にお使いください。尚、openweathermap.orgより
アカウントを作成後、APIKEYを取得しお使いください。
下記のソースコードをコピーしての可変等は可能です。余談
天気予報の絵文字が合致していていないかもしれません。
また都道府県のIDもズレている場合、お好みで変更ください。
ZIPコードで情報を取得するとより正確な天気予報となるそうです。下記のコードを実行するとこんな感じになります。
原文:天気予報を取得するアレを使用してみた(Openweathermap_api)。
Openweathermap_api.php<?php class Openweathermap_api{ public $url = "https://api.openweathermap.org/data/2.5/weather?id="; public $appid = "apikey"; public $ken =""; public $response =""; public $icon = array( "01d"=>"☀", "02d"=>"⛅", "03d"=>"☁", "04d"=>"?",//☁ "09d"=>"?", "010d"=>"?", "011d"=>"⛈", "013d"=>"❄", "050d"=>"?", ); function __construct() { $this->ken = (object)(json_decode(@file_get_contents("ken.json"),true)); } function api(){ $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $this->url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); $this->response = (object)json_decode(curl_exec($ch),true); curl_close($ch); } } $tenki = New Openweathermap_api(); $tenki->url = "https://api.openweathermap.org/data/2.5/weather?id=".$tenki->ken->kochi["id"]."&appid=".$tenki->appid; $tenki->api(); print($tenki->icon[str_replace("n","d",$tenki->response->weather[0]["icon"])]); var_dump($tenki->response);ken.json{ "hokkaido": { "id": "2130037", "kenmei": "北海道", "kenfurigana": "ほっかいどう" }, "aomori": { "id": "2130656", "kenmei": "青森県", "kenfurigana": "あおもり" }, "iwate": { "id": "2112518", "kenmei": "岩手県", "kenfurigana": "いわて" }, "miyagi": { "id": "2111888", "kenmei": "宮城県", "kenfurigana": "みやぎ" }, "akita": { "id": "2113124", "kenmei": "秋田県", "kenfurigana": "あきた" }, "yamagata": { "id": "2110554", "kenmei": "山形県", "kenfurigana": "やまがた" }, "fukushima": { "id": "2112923", "kenmei": "福島県", "kenfurigana": "ふくしま" }, "ibaraki": { "id": "2112669", "kenmei": "茨城県", "kenfurigana": "いばらき" }, "tochigi": { "id": "1850310", "kenmei": "栃木県", "kenfurigana": "とちぎ" }, "gunma": { "id": "1863501", "kenmei": "群馬県", "kenfurigana": "ぐんま" }, "saitama": { "id": "1853226", "kenmei": "埼玉県", "kenfurigana": "さいたま" }, "chiba": { "id": "2113014", "kenmei": "千葉県", "kenfurigana": "ちば" }, "tokyo": { "id": "1850144", "kenmei": "東京都", "kenfurigana": "とうきょう" }, "kanagawa": { "id": "1860291", "kenmei": "神奈川県", "kenfurigana": "かながわ" }, "niigata": { "id": "1855429", "kenmei": "新潟県", "kenfurigana": "にいがた" }, "toyama": { "id": "1849872", "kenmei": "富山県", "kenfurigana": "とやま" }, "ishikawa": { "id": "1861387", "kenmei": "石川県", "kenfurigana": "いしかわ" }, "fukui": { "id": "1863983", "kenmei": "福井県", "kenfurigana": "ふくい" }, "yamanashi": { "id": "1848649", "kenmei": "山梨県", "kenfurigana": "やまなし" }, "nagano": { "id": "1856210", "kenmei": "長野県", "kenfurigana": "ながの" }, "gifu": { "id": "1863640", "kenmei": "岐阜県", "kenfurigana": "ぎふ" }, "shizuoka": { "id": "1851715", "kenmei": "静岡県", "kenfurigana": "しずおか" }, "aichi": { "id": "1865694", "kenmei": "愛知県", "kenfurigana": "あいち" }, "mie": { "id": "1857352", "kenmei": "三重県", "kenfurigana": "みえ" }, "shiga": { "id": "1852553", "kenmei": "滋賀県", "kenfurigana": "しが" }, "kyoto": { "id": "1857907", "kenmei": "京都府", "kenfurigana": "きょうと" }, "osaka": { "id": "1853909", "kenmei": "大阪府", "kenfurigana": "おおさか" }, "hyogo": { "id": "1862047", "kenmei": "兵庫県", "kenfurigana": "ひょうご" }, "nara": { "id": "1855608", "kenmei": "奈良県", "kenfurigana": "なら" }, "wakayama": { "id": "1848938", "kenmei": "和歌山県", "kenfurigana": "わかやま" }, "tottori": { "id": "1849890", "kenmei": "鳥取県", "kenfurigana": "とっとり" }, "shimane": { "id": "1852442", "kenmei": "島根県", "kenfurigana": "しまね" }, "okayama": { "id": "1854381", "kenmei": "岡山県", "kenfurigana": "おかやま" }, "hiroshima": { "id": "1862413", "kenmei": "広島県", "kenfurigana": "ひろしま" }, "yamaguchi": { "id": "1848681", "kenmei": "山口県", "kenfurigana": "やまぐち" }, "tokushima": { "id": "1850157", "kenmei": "徳島県", "kenfurigana": "とくしま" }, "kagawa": { "id": "1860834", "kenmei": "香川県", "kenfurigana": "かがわ" }, "ehime": { "id": "1864226", "kenmei": "愛媛県", "kenfurigana": "えひめ" }, "kochi": { "id": "1859133", "kenmei": "高知県", "kenfurigana": "こうち" }, "fukuoka": { "id": "1863958", "kenmei": "福岡県", "kenfurigana": "ふくおか" }, "saga": { "id": "1853303", "kenmei": "佐賀県", "kenfurigana": "さが" }, "nagasaki": { "id": "1856156", "kenmei": "長崎県", "kenfurigana": "ながさき" }, "kumamoto": { "id": "1858419", "kenmei": "熊本県", "kenfurigana": "くまもと" }, "oita": { "id": "1854484", "kenmei": "大分県", "kenfurigana": "おおいた" }, "miyazaki": { "id": "1856710", "kenmei": "宮崎県", "kenfurigana": "みやざき" }, "kagoshima": { "id": "1860825", "kenmei": "鹿児島県", "kenfurigana": "かごしま" }, "okinawa": { "id": "1854345", "kenmei": "沖縄県", "kenfurigana": "おきなわ" } }
- 投稿日:2020-02-19T19:22:55+09:00
【Laravel】日付処理ならCarbonにお任せ!!
PHPでは現在時刻を取得したり、一年後の日付を取得したりすることができる
「DateTimeクラス」がありますが、これがまた少し使いにくい、、、
そんな時に出てくるのがCarbonです!!
CarbonはDateTimeクラスを継承しており、言うなればDateTimeをもっと使いやすくしたクラスです。
しかも、PHPで人気なフレームワークLaravelには標準でインストールされています
Laravel内でupdated_atやcreated_atはCarbonインスタンスでできているらしい!!
というわけで、Laravelを使っているのであれば、使うしかないという状況です。使用可能なクラスはCarbon、CarbonImmutableの2つ
こちらの章は細かいことについて書いているので読み飛ばしてもらっても大丈夫です
使用可能なクラスはCarbonとCarbonImmutableです
どちらのクラスとも同じメソッドを使えます
しかし、インスタンスからメソッドを呼び出した時の挙動が少し違います
下記の例で確認しましょう//インスタンス作成 $mutable = Carbon::now(); $immutable = CarbonImmutable::now(); //1日後の日付を取得する $modifiedMutable = $mutable->add(1, 'day'); $modifiedImmutable = $immutable->add(1, 'day'); //Carbonクラスの場合、返り値と元のインスタンスの値が同じになる var_dump($modifiedMutable === $mutable); // bool(true) var_dump($mutable->isoFormat('dddd D')); // string(11) "Saturday 15" var_dump($modifiedMutable->isoFormat('dddd D')); // string(11) "Saturday 15" //CarbonImmutableクラスの場合、返り値と元のインスタンスの値は異なる var_dump($modifiedImmutable === $immutable); // bool(false) var_dump($immutable->isoFormat('dddd D')); // string(9) "Friday 14" var_dump($modifiedImmutable->isoFormat('dddd D')); // string(11) "Saturday 15"Carbonクラスはメソッドを呼び出したインスタンスが書き換えられる
CarbonImmutableクラスはメソッドを呼び出したインスタンスはそのままになるCarbon、CarbonImmutableは相互変換可能
Carbon、CarbonImmutableは相互に変換可能です
下記のようにtoMutable()
、toImmutable()
メソッドを使用することで相互変換できます
toMutable()
メソッドはCarbonImmutable
クラスをCarbon
クラスに変換します
toImmutable()
メソッドはCarbon
クラスをCarbonImmutable
クラスに変換しますちなみに
isMutable()
メソッドはCarbon
かどうかを判定します
isImmutable()
メソッドはCarbonImmutable
かどうかを判定します<?php use Carbon\Carbon; $mutable = CarbonImmutable::now()->toMutable(); var_dump($mutable->isMutable()); // bool(true) var_dump($mutable->isImmutable()); // bool(false) $immutable = Carbon::now()->toImmutable(); var_dump($immutable->isMutable()); // bool(false) var_dump($immutable->isImmutable()); // bool(true)CarbonクラスとCarbonImmutableクラスは同じメソッドが使えるようなので、
CarbonImmutableクラスでも同じ方法で使えるはずです以下に使い方の例を記載するので、活用してください
インスタンス作成方法
<?php use Carbon\Carbon; $carbon = new Carbon(); $now = Carbon::now(); $nowInLondonTz = Carbon::now('Europe/London'); $date = Carbon::now('+13:30'); $today = Carbon::today(); $tomorrow = Carbon::tomorrow(); $yesterday = Carbon::yesterday(); $tomorrow = Carbon::tomorrow('Europe/London'); // オリンピックの開会式の時間を変数に設定 $year = 2020; $month = 7; $day = 24; $hour = 20; $minute = 00; $second = 00; $tz = 'Asia/Tokyo'; Carbon::createFromDate($year, $month, $day, $tz); Carbon::createMidnightDate($year, $month, $day, $tz); Carbon::createFromTime($hour, $minute, $second, $tz); Carbon::create($year, $month, $day, $hour, $minute, $second, $tz); $dt = new Carbon('2020-02-15'); echo $dt->copy()->subDay(); // 2020-02-15 00:00:00 echo $dt->subDay(); // 2020-02-15 00:00:00ゲッター
<?php use Carbon\Carbon; $dt = Carbon::parse('2012-10-5 23:26:11.123789'); $dt->year; // int(2012) $dt->month; // int(10) $dt->day; // int(5) $dt->hour; // int(23) $dt->minute; // int(26) $dt->second; // int(11) $dt->micro; // int(123789) $dt->dayOfWeek; // int(5) $dt->dayOfWeekIso; // int(5) $dt->englishDayOfWeek; // string(6) "Friday" $dt->shortEnglishDayOfWeek; // string(3) "Fri" $dt->locale('de')->dayName; // string(7) "Freitag" $dt->locale('de')->shortDayName; // string(3) "Fr." $dt->locale('de')->minDayName; // string(2) "Fr" $dt->englishMonth; // string(7) "October" $dt->shortEnglishMonth; // string(3) "Oct" $dt->locale('de')->monthName; // string(7) "Oktober" $dt->locale('de')->shortMonthName; // string(3) "Okt" $dt->localeDayOfWeek; // string(7) "Freitag" $dt->shortLocaleDayOfWeek; // string(2) "Fr" $dt->localeMonth; // string(7) "Oktober" $dt->shortLocaleMonth; // string(3) "Okt" $dt->dayOfYear; // int(279) $dt->weekNumberInMonth; // int(1) $dt->weekOfMonth; // int(1) $dt->weekOfYear; // int(40) $dt->daysInMonth; // int(31) $dt->timestamp; // int(1349479571) Carbon::now()->timezoneName; // UTC Carbon::now()->tzName; // UTC比較
$first->equalTo($second); $first->notEqualTo($second); $first->greaterThan($second); $first->greaterThanOrEqualTo($second); $first->lessThan($second); $first->lessThanOrEqualTo($second); Carbon::create(2012, 9, 5, 5)->between($first, $second, false); $dt = Carbon::now(); $dt2 = Carbon::createFromDate(1987, 4, 23); $dt->isSameAs('w', $dt2); $dt->isFuture(); $dt->isPast(); $dt->isSameYear($dt2); $dt->isCurrentYear(); $dt->isNextYear(); $dt->isLastYear(); $dt->isLeapYear(); $dt->isCurrentMonth(); $dt->isNextMonth(); $dt->isLastMonth(); $dt->isWeekday(); $dt->isWeekend(); $dt->isMonday(); $dt->isTuesday(); $dt->isWednesday(); $dt->isThursday(); $dt->isFriday(); $dt->isSaturday(); $dt->isSunday(); $dt->isLastOfMonth(); $dt->is('Sunday'); $dt->is('June'); $dt->is('2019'); $dt->is('12:23'); $dt->is('2 June 2019'); $dt->isSameDay($dt2); $dt->isCurrentDay(); $dt->isYesterday(); $dt->isToday(); $dt->isTomorrow(); $dt->isNextWeek(); $dt->isLastWeek(); $dt->isSameHour($dt2); $dt->isCurrentHour(); $dt->isSameMinute($dt2); $dt->isCurrentMinute(); $dt->isSameSecond($dt2); $dt->isCurrentSecond(); $born->isBirthday($noCake); $born->isBirthday($yesCake); $overTheHill->isBirthday();足し算、引き算
<?php use Carbon\Carbon; $dt = Carbon::create(2012, 1, 31, 0); echo $dt->toDateTimeString(); // 2012-01-31 00:00:00 echo $dt->addCenturies(5); // 2512-01-31 00:00:00 echo $dt->addCentury(); // 2612-01-31 00:00:00 echo $dt->subCentury(); // 2512-01-31 00:00:00 echo $dt->subCenturies(5); // 2012-01-31 00:00:00 echo $dt->addYears(5); // 2017-01-31 00:00:00 echo $dt->addYear(); // 2018-01-31 00:00:00 echo $dt->subYear(); // 2017-01-31 00:00:00 echo $dt->subYears(5); // 2012-01-31 00:00:00 echo $dt->addQuarters(2); // 2012-07-31 00:00:00 echo $dt->addQuarter(); // 2012-10-31 00:00:00 echo $dt->subQuarter(); // 2012-07-31 00:00:00 echo $dt->subQuarters(2); // 2012-01-31 00:00:00 echo $dt->addMonths(60); // 2017-01-31 00:00:00 echo $dt->addMonth(); // 2017-03-03 00:00:00 echo $dt->subMonth(); // 2017-02-03 00:00:00 echo $dt->subMonths(60); // 2012-02-03 00:00:00 echo $dt->addDays(29); // 2012-03-03 00:00:00 echo $dt->addDay(); // 2012-03-04 00:00:00 echo $dt->subDay(); // 2012-03-03 00:00:00 echo $dt->subDays(29); // 2012-02-03 00:00:00 echo $dt->addWeekdays(4); // 2012-02-09 00:00:00 echo $dt->addWeekday(); // 2012-02-10 00:00:00 echo $dt->subWeekday(); // 2012-02-09 00:00:00 echo $dt->subWeekdays(4); // 2012-02-03 00:00:00 echo $dt->addWeeks(3); // 2012-02-24 00:00:00 echo $dt->addWeek(); // 2012-03-02 00:00:00 echo $dt->subWeek(); // 2012-02-24 00:00:00 echo $dt->subWeeks(3); // 2012-02-03 00:00:00 echo $dt->addHours(24); // 2012-02-04 00:00:00 echo $dt->addHour(); // 2012-02-04 01:00:00 echo $dt->subHour(); // 2012-02-04 00:00:00 echo $dt->subHours(24); // 2012-02-03 00:00:00 echo $dt->addMinutes(61); // 2012-02-03 01:01:00 echo $dt->addMinute(); // 2012-02-03 01:02:00 echo $dt->subMinute(); // 2012-02-03 01:01:00 echo $dt->subMinutes(61); // 2012-02-03 00:00:00 echo $dt->addSeconds(61); // 2012-02-03 00:01:01 echo $dt->addSecond(); // 2012-02-03 00:01:02 echo $dt->subSecond(); // 2012-02-03 00:01:01 echo $dt->subSeconds(61); // 2012-02-03 00:00:00 echo $dt->addMilliseconds(61); // 2012-02-03 00:00:00 echo $dt->addMillisecond(); // 2012-02-03 00:00:00 echo $dt->subMillisecond(); // 2012-02-03 00:00:00 echo $dt->subMillisecond(61); // 2012-02-03 00:00:00 echo $dt->addMicroseconds(61); // 2012-02-03 00:00:00 echo $dt->addMicrosecond(); // 2012-02-03 00:00:00 echo $dt->subMicrosecond(); // 2012-02-03 00:00:00 echo $dt->subMicroseconds(61); // 2012-02-03 00:00:00 echo $dt->add(61, 'seconds'); // 2012-02-03 00:01:01 echo $dt->sub('1 day'); // 2012-02-02 00:01:01 echo $dt->add(CarbonInterval::months(2)); // 2012-04-02 00:01:01 echo $dt->subtract(new DateInterval('PT1H')); // 2012-04-01 23:01:01差
<?php use Carbon\Carbon; echo Carbon::now('America/Vancouver')->diffInSeconds(Carbon::now('Europe/London')); // 0 $dtOttawa = Carbon::createMidnightDate(2000, 1, 1, 'America/Toronto'); $dtVancouver = Carbon::createMidnightDate(2000, 1, 1, 'America/Vancouver'); echo $dtOttawa->diffInHours($dtVancouver); // 3 echo $dtVancouver->diffInHours($dtOttawa); // 3 echo $dtOttawa->diffInHours($dtVancouver, false); // 3 echo $dtVancouver->diffInHours($dtOttawa, false); // -3 $dt = Carbon::createMidnightDate(2012, 1, 31); echo $dt->diffInDays($dt->copy()->addMonth()); // 31 echo $dt->diffInDays($dt->copy()->subMonth(), false); // -31 $dt = Carbon::createMidnightDate(2012, 4, 30); echo $dt->diffInDays($dt->copy()->addMonth()); // 30 echo $dt->diffInDays($dt->copy()->addWeek()); // 7 $dt = Carbon::createMidnightDate(2012, 1, 1); echo $dt->diffInMinutes($dt->copy()->addSeconds(59)); // 0 echo $dt->diffInMinutes($dt->copy()->addSeconds(60)); // 1 echo $dt->diffInMinutes($dt->copy()->addSeconds(119)); // 1 echo $dt->diffInMinutes($dt->copy()->addSeconds(120)); // 2 echo $dt->addSeconds(120)->secondsSinceMidnight(); // 120人との違い
<?php use Carbon\Carbon; $dt = CarbonImmutable::create(2017, 1, 31, 0); echo $dt->addMonth(); // 2017-03-03 00:00:00 echo $dt->subMonths(2); // 2016-12-01 00:00:00定数
<?php use Carbon\Carbon; var_dump(Carbon::SUNDAY); // int(0) var_dump(Carbon::MONDAY); // int(1) var_dump(Carbon::TUESDAY); // int(2) var_dump(Carbon::WEDNESDAY); // int(3) var_dump(Carbon::THURSDAY); // int(4) var_dump(Carbon::FRIDAY); // int(5) var_dump(Carbon::SATURDAY); // int(6) var_dump(Carbon::YEARS_PER_CENTURY); // int(100) var_dump(Carbon::YEARS_PER_DECADE); // int(10) var_dump(Carbon::MONTHS_PER_YEAR); // int(12) var_dump(Carbon::WEEKS_PER_YEAR); // int(52) var_dump(Carbon::DAYS_PER_WEEK); // int(7) var_dump(Carbon::HOURS_PER_DAY); // int(24) var_dump(Carbon::MINUTES_PER_HOUR); // int(60) var_dump(Carbon::SECONDS_PER_MINUTE); // int(60)以上です!!!
ここまで読んでいただきありがとうございました!!
疑問、気になるところがございましたら、質問、コメントよろしくお願いします!!!
- 投稿日:2020-02-19T19:15:05+09:00
【PHP】就職活動の為の、webアプリ(ポートフォリオ)設計図公開!|未経験からエンジニアへ
web系エンジニアを目指し、PHPを学習している初学者です。
就職活動の武器とすべく着手した、webアプリ(ポートフォリオ)作成。
MENTAを利用し、本格的に学習開始してから4ヶ月で、デプロイに漕ぎ着けました!
派手さもモダンな感じもないですが、バリデーションや不正アクセス防止など、地味な部分を丁寧にコーディングしました。
採用担当の方、同じエンジニアを目指す初学者の方、エンジニアを目指そうか迷っている方の目に留まれば幸いです。記事の目的
- 面接に備えた補助資料として
- 同じ境遇の方の参考(になれば幸い)
作成した【内定者懇親サイト】について、
1. カタログ
2. 仕様書
3. 気を付けた点
4. 後悔している点
をまとめました。1.カタログ
作成したサイトの紹介。
〜内定者懇親サイト〜
内定承諾してから、入社するまでの期間。
「他の内定者は何人位?年齢は?どんな人?」
「内定式で会う前に知って欲しい・知っておきたい、話のネタを仕込んでおきたい。」
そんな願いを叶える、簡易的な懇親サイト。概要
ユーザー種類
- 管理者
- メンバー
機能
- 管理者|メンバー全員の編集、削除。他の管理者の新規登録、編集、削除
- メンバー|自身の登録、編集、削除。他のメンバー 一覧、詳細の閲覧
開発環境
MAMPでローカル環境構築。
VScodeでコーディング→Githubでコード管理→herokuでデプロイ
- PHP 7.3.11
- HTML/CSS、Bootstrap4
- MySQL 5.7.26
2.仕様書
サイトの設計図です。
機能一覧
- メンバーのCRUD機能(新規登録、プロフィール編集、削除)
- 管理者のCRUD機能
- 管理者権限付与(メンバーの編集、削除)
- メンバー 一覧表示機能
- メンバー 詳細表示機能
- レスポンシブ対応(Bootstrap)
ER図
ステートチャート図
画面遷移図
これらは無料で使えるLucidchartを利用し、作成しました。3.気を付けた点
基本スキルを示す
- フレームワークを使わない、スクラッチ開発(フロント部分はBootstrap使用)
- CRUD
- 一通りの入力形式(テキストボックス、チェックボックス、ラジオボタン、ファイルのアップロード)実装
- 各項目に対するバリデーションを丁寧に
- パスワードのハッシュ化 (
PASSWORD_DEFAULT
使用)- 不正アクセス防止
ログイン
- メンバーログインと新規登録、管理者ログインを1つのログイン画面にまとめ、
login_check.php
にて、移行画面を変更した- バリデーションはメソッドを呼び出し、返り値はboolean型とした
login_check.phpclass Login { public function __construct() { 2.validation $email_validation = new emailValidation(); $is_email = $email_validation->isEmail($this->clean['email']); //パスワードも同様に //validationエラーなら、エラーメッセージを取得し、ログイン画面へ戻る } public function main() { 1.DB接続し、メンバーテーブル・管理者テーブルの情報と、入力された情報を照合 メール 一致なし =>新規登録画面へ メール、パスワード メンバーと一致 =>メンバーログイン 管理者と一致 =>管理者ログイン メール 一致、パスワード 一致なし =>エラーメッセージを取得し、ログイン画面へ戻る } } $login = new Login(); $login->main();新規登録
- パスワードの再入力は、ログインユーザーの邪魔にならないよう新規登録画面で行った
入力値を
htmlspecialchars
処理する為に、hsc.php
にデータを渡すが、配列(3つ選択させるチェックボックス)も同様の処理が出来るようにしたhsc.phpclass Hsc { public static function clean($posts) { foreach ($posts as $post => $value) { 3.配列の場合 if(is_array($value)) { foreach($value as $key => $val) { $clean[$post][$key] = htmlspecialchars($val, ENT_QUOTES, 'UTF-8'); } } else { $clean[$post] = htmlspecialchars($value, ENT_QUOTES, 'UTF-8'); } } return $clean; } }アラート表示
$status
で、前画面での処理内容を表示したlist.phpの場合<?php if(!empty($status)): ?> <div class="alert alert-success" role="alert"> <?php switch ($status) { case 'login': echo 'ログイン成功しました。'; break; case 'new': echo '新規登録が完了しました。'; break; case 'edit': echo '編集が完了しました。'; break; case 'delete': echo '削除が完了しました。'; break; } ?> </div> <?php endif; ?>4.後悔していること
- 開発履歴を、Githubのブランチやissuesを使用して残せば良かった(ずっとmasterにpushし、コメントも「third commit」など無意味なものばかり^^;)
- 自身の困りごとを元に、実用性の高いものにすれば良かった
- クラスをあまり活用出来なかった
- Twitter的な交流(コメント、イイね!)がない
- ソートがない
- 変数の付け方、仕様書を定めずに着手してしまった
- 後から「アラート付けよう!」など追加していったので、無駄な修正作業や、抜け・漏れで新たなエラーを生み出してしまった
以上です。
Twitter的な機能やソートについては、追加実装するかもしれませんが、ひとまずはこれでデプロイ。
コーディングして画面が出来上がってからは、夢中で作成することが出来ました。
ぜひ、サイトにアクセスしてみてください!
https://github.com/kunitani920/BullentinBoard
- 投稿日:2020-02-19T18:31:51+09:00
php-fpmとfastcgiを使ってphpを実行する
恒例
FastCGIに関して
https://ja.wikipedia.org/wiki/FastCGIFPMに関して
http://php.net/manual/zh/install.fpm.php
https://php-fpm.org/php-fpm Installation
Yumでインストールする
yum install php55w-fpm #php5.5の場合 yum install php56w-fpm #php5.6の場合 yum install php70w-fpm #php7.0の場合自分でcompileでインストールする
--enable-fpmというペラメタつけてphpをコンパイルする
例えば./configure --prefix=/usr/local/php --with-apxs2=/usr/local/httpd/bin/apxs --with-zlib --with-mysql=mysqlnd --with-mysqli --enable-mbstring --enable-ftp --with-xsl --with-gd --with-jpeg-dir=/usr/local/libjpeg --with-png-dir=/usr/local/libpng --with-freetype-dir --with-pdo-mysql --with-openssl --enable-soap --with-mcrypt --enable-zip --with-tidy --with-curl --enable-gd-native-ttf --enable-bcmath --enable-sockets --enable-exif --with-gettext --with-ldap --enable-fpm --with-fpm-user=fpm-user --with-fpm-group=fpm-group--enable-fpm
--with-fpm-user=fpm-user
--with-fpm-group=fpm-groupfpm-userとfpm-groupをサーバーのユーザーに替えてください
FastCGI Installation
Yumでインストールする
bash
yum install fcgi-devel fcgi
自分でcompileでインストールする
https://httpd.apache.org/mod_fcgid/ からmod_fcgidをダウンロードするtar zxf mod_fcgid-2.3.9.tar.gz cd mod_fcgid-2.3.9/ APXS=/usr/local/httpd/bin/apxs ./configure.apxs make make installhttpd.confを編集する
#追加する LoadModule fcgid_module modules/mod_fcgid.so LoadModule proxy_fcgi_module modules/mod_proxy_fcgi.so #追加する <IfModule fcgid_module> AddHandler fcgid-script .php FcgidWrapper "/usr/local/php/bin/php-cgi" .php #自分のphpのpathに替えてください </IfModule> #追加する <IfModule fcgid_module> AddHandler fcgid-script .php AddHandler fcgid-script .fcgi FcgidWrapper "/usr/local/php/bin/php-cgi" .php #自分のphpのpathに替えてください <FilesMatch \.php$> SetHandler "proxy:fcgi://127.0.0.1:9000" </FilesMatch> </IfModule>php-fpm.confを編集する
; Unix user/group of processes ; Note: The user is mandatory. If the group is not set, the default user's group ; will be used. user = fpm-user group = fpm-group listen = 127.0.0.1:9000 ; listen = /usr/local/php/var/run/socket #socket と port 2つlisten方法がある、一つを選んでくださいphp-fpmをスタート
/usr/local/php/sbin/php-fpmphpinfo()で確認する
Server API は FPM/FastCGIで表示されると成功!
- 投稿日:2020-02-19T16:34:27+09:00
laradoc環境作成でmysql接続でつまずいた話
laradock環境にて::ERROR 2002 (HY000): Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock'
事象
php artisan migrate上記コマンドを流すと、タイトルのエラーが発生。。。
いやぁまいったな。。。。
とりあえずググるか。。。
某記事1 DB_HOST=localhostとしてください。
ふむふむやってみよう。。。
数十秒後
できねぇな、、、
某記事2 DB_HOST=127.0.0.1としてください。
ほんとか。。!?
数十秒後
やっぱりできんやないかい。。。
解決策
どうやら立ち上がっているコンテナに紐付けられている
HOSTにしなければいけないみたい。。。
なるほどね。
ってことで下記手順プロジェクト配下で
docker-compose exec mysql /bin/bash下記で一番下に出てきたIPをDB_HOSTに記載!
cat /etc/hostsんで改めてmigrateコマンド実行するとうまくいきました!!!
いやぁまいったね。。。
- 投稿日:2020-02-19T14:27:46+09:00
Laravelのリソースコントローラ
laravelのリソースコントローラについてのメモです。
リソースコントローラ
リソースコントローラを使うとアプリの基本的な操作であるCRUD(作成、一覧表示、編集、削除)などのアクションやそのルーティングが自動的にされます。
例えばusersのリソースコントローラだと下のようなアクションが自動で作られます。
HTTPメソッド URI アクション ルート名 GET /users index users.index GET /users/create create users.create POST /users store users.store GET /users/{user} show users.show GET /users/{user}/edit edit users.edit PUT/PATCH /users/{user} update users.update DELETE /users/{user} destroy users.destroy 作成
コントローラをつくるartisanコマンドに
--resource
をつけます。php artisan make:controller UsersController --resource
すると自動的にコントローラ内にこれらのアクションが用意されます。
UsersController.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class UsersController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { // } /** * Show the form for creating a new resource. * * @return \Illuminate\Http\Response */ public function create() { // } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { // } /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function show($id) { // } /** * Show the form for editing the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function edit($id) { // } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, $id) { // } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy($id) { // } }ルーティング
web.phpRoute::resource('users', 'UsersController');これだけですべてのアクションの紐づけができます。
また使うアクションを限定することもできます。作成、一覧表示のみを行う場合↓
web.php//作成、一覧表示のみを行う場合 Route::resource('users', 'UsersController', ['only' => ['index', 'create', 'store', 'show']]);
- 投稿日:2020-02-19T14:27:46+09:00
Laravelのリソースコントローラを使ってCRUDアクション作成
laravelのリソースコントローラについてのメモです。
リソースコントローラ
リソースコントローラを使うとアプリの基本的な操作であるCRUD(作成、一覧表示、編集、削除)などのアクションやそのルーティングが自動的にされます。
例えばusersのリソースコントローラだと下のようなアクションが自動で作られます。
HTTPメソッド URI アクション ルート名 GET /users index users.index GET /users/create create users.create POST /users store users.store GET /users/{user} show users.show GET /users/{user}/edit edit users.edit PUT/PATCH /users/{user} update users.update DELETE /users/{user} destroy users.destroy 作成
コントローラをつくるartisanコマンドに
--resource
をつけます。php artisan make:controller UsersController --resource
すると自動的にコントローラ内にこれらのアクションが用意されます。
UsersController.php<?php namespace App\Http\Controllers; use Illuminate\Http\Request; class UsersController extends Controller { /** * Display a listing of the resource. * * @return \Illuminate\Http\Response */ public function index() { // } /** * Show the form for creating a new resource. * * @return \Illuminate\Http\Response */ public function create() { // } /** * Store a newly created resource in storage. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { // } /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function show($id) { // } /** * Show the form for editing the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function edit($id) { // } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, $id) { // } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy($id) { // } }ルーティング
web.phpRoute::resource('users', 'UsersController');これだけですべてのアクションの紐づけができます。
また使うアクションを限定することもできます。作成、一覧表示のみを行う場合↓
web.php//作成、一覧表示のみを行う場合 Route::resource('users', 'UsersController', ['only' => ['index', 'create', 'store', 'show']]);
- 投稿日:2020-02-19T13:47:58+09:00
PHPでプレースホルダを使ったフォーム作成
PHPでフォーム作成
以前の記事で、DVWAでは変数をSQL文にそのままいれたことから、SQLインジェクションが可能なコードとなってしまっていました。
そこで今回は、そんなSQLインジェクションに対処するための方法として、プレースホルダについて紹介したいと思います。
プレースホルダとは?
プレースホルダはその名の通り、SQL文に対して後から値をセットするための場所を確保する機能となっています。
プレースホルダは、疑問符プレースホルダの?、名前付きプレースホルダの:値、で表現されまます。
また、後から入れる値のバインド値のことを、プリペアドステートメント(予約文)と言います。
このプレースホルダを使うことによって、入力値から直接SQLインジェクションが行われることを、回避できるというわけです。
HTML/PHP/MySQLでフォーム作成
ここでは、実際にフォームを作成し、プレースホルダを使うコードについて記載していきたいと思います。
コードは下記の記事を参考にしています。
https://noumenon-th.net/programming/2016/01/18/mysql-2/前提条件
- PHP 5.46
- MySQL 14.14
MySQLでDB、テーブル、カラムの設定
まずは、MySQLでDBとテーブルとカラムをセットしていきます。
ここではDBをtest1、テーブルをname_list、カラムをid・nameでセットします。
# mysql -u root -p mysql> CREATE DATABASE test1; mysql> USE test1; mysql> CREATE TABLE name (id INT NOT NULL AUTO_INCREMENT PRIMARY KEY,name TEXT NOT NULL) DEFAULT CHARACTER SET=utf8;フォームのHTMLファイルを作成
まず基本となる簡単な、フォームをHTMLで記載していきます。
index.html<!DOCTYPE html> <html> <head> <title>データを入力する</title> <meta charset="utf-8"> </head> <body> <h1>フォーム画面</h1> <form action="form.php" method="post"> 名前を入力:<input type="text" name="name"> <input type="submit" value="登録する"> </form> </body> </html>フォーム情報を登録するPHPファイル作成
次に、フォーム情報をMySQLに登録するPHPファイルを作成していきます。
SQL文はプレースホルダを使って表示していきます。
form.php<?php header("Content-type: text/html; charset=utf-8"); //データベース接続 $server = "IPアドレス"; $userName = "MySQLのユーザー名"; $password = "MySQLのパスワード"; $dbName = "test1"; $mysqli = new mysqli($server, $userName, $password, $dbName); if ($mysqli->connect_error){ echo $mysqli->connect_error; exit(); }else{ $mysqli->set_charset("utf-8"); } if(empty($_POST)) { echo "<a href='index.php'>index.php</a>←登録はこのページから"; }else{ //名前入力判定 if (!isset($_POST['name']) || $_POST['name'] === "" ){ echo "名前が入力されていません。"; }else{ //プリペアドステートメントの設定(SQL文を最初に用意して、その後はクエリ内のパラメーターの値だけを変更する) $stmt = $mysqli->prepare("INSERT INTO name_list (name) VALUES (?)"); if($stmt){ //プレースホルダに値を設定する、bind_paramsの第一引数は文字列が入るので's' $stmt->bind_param('s', $name); $name = $_POST['name']; //登録する名前をhtml表記、クオテーションを取った状態で表示 if($stmt->execute()){ echo htmlspecialchars($name, ENT_QUOTES, 'UTF-8')."さんを登録しました"; }else{ echo $stmt->errno . $stmt->error; } $stmt->close(); }else{ echo $mysqli->errno . $mysqli->error; } } } // データベース切断 $mysqli->close(); ?>実際にはこんな感じに動作します。
これで、プレースホルダを利用したPHPのフォーム作成は完了です。
- 投稿日:2020-02-19T13:00:57+09:00
docker環境のメールはmailhogで決まり
docker環境でメールどうしよう問題
- 直接送りゃいいんじゃね?
- いやいや、事故るっしょ。1万通とかメール送信してしもたら・・・
- そのためだけにsendgridとかmailgunとか
- おおげさ
- postfixのコンテナあげる?
- 環境つくるだけで一苦労しそう(docker-hubにあるけど)
ということでいろいろ探してたらMailHogというものを発見しました
- メリット
- 事故らない
- いくらメール投げてもローカルにしかとどまらないので
- 設定が簡単
- WEB UIでメール確認ができる
- デメリット
- 日本語メールは文字化けすることがある、UTF-8でおねがいしたい
- なぜかdockerコンテナが死ぬことがある、まあコンテナのリスタートしてください
Howto
1. docker-compose.ymlにはこれだけ追加するだけ
docker-compose.ymlmailhog: image: mailhog/mailhog ports: - "8025:8025"2. mhsendmailを入れてください
- https://github.com/mailhog/mhsendmail
- goで出来ています
- yumとかaptでsendmailいちいち入れるの面倒なので、こいつをマウントしてやれば良い
- 例えばこんな感じ
docker-compose.ymlvolumes: - "./bin/mhsendmail:/usr/local/bin/mhsendmail"3. phpの人向け
- webサーバのコンテナのphp.iniに追加(変更)しておくと、phpの標準mail関数でメール送信できますんで既存コードをいじらなくて済む
php.inisendmail_path = "/usr/local/bin/mhsendmail --smtp-addr=mailhog:1025"以上です、快適なdockerライフを!!
- 投稿日:2020-02-19T11:48:15+09:00
phpのshort_open_tagがOffの場合のエラー内容が分かりづらかった
phpでviewをテンプレートエンジンとして実装している際に以下のような記載をしたところ
以下のようにエラーになりました。<?php if ($is_ok): ?> <p><?php echo $message1; ?></p> <?php else: ?> <p><?php echo $message2; ?></p> <? endif; ?>エラー内容Fatal Error - Method Fuel\Core\View::__toString() must not throw an exception, caught ParseError: syntax error, unexpected end of file in /XXX/XXX.php on line 0調べてみると、
<? endif; ?>
この部分が誤字脱字でした。
short_open_tag
の指定が必要でした。short_open_tagとは?
php.iniで
short_open_tag
をONにすると<?php
を<?
として省略できます。
が、このphp指定が抜けていたのでおかしくなったようです。エラー内容が分かりづらい。。
ちなみにphp7.3でもデフォルト値はOnとコメント記載があったのに
設定自体はOffになっていました。デフォルト設定; short_open_tag ; Default Value: On ; Development Value: Off ; Production Value: Offphp7.4からは
<?
はDeprecatedとなりphp8からは廃止される予定のようなので変わったのかな?
- 投稿日:2020-02-19T10:58:19+09:00
[備忘メモ] PHP で各位の IP アドレスを取得する
現在ページをみているユーザのIP
こいつは簡単。
$_SERVER['REMOTE_ADDR'];Laravel なら下記でも取得できる。
\Request::ip()プログラム実行しているサーバのIP
こいつは少々厄介。
複数台でサーバ分散されてると特に。まずは、
$_SERVER
を使うパターン。$_SERVER['SERVER_ADDR'];ただ、上記だとサーバのプライベートIPが取れてしまい、グローバルIPが取れないことがある。
そのため、グローバルIPが欲しい場合、以下を使う。$hostname = "www.google.com"; $ip = gethostbyname($hostname);上記ならグローバルIPが取れる。
ただ、サーバ複数で分散してるとダメ。なので、下記を使う。
$ip = rtrim(`curl inet-ip.info 2>/dev/null`);多分上手くいくはず。
- 投稿日:2020-02-19T09:23:20+09:00
テーマに正しくjsファイル、スタイルシートを読み込ませる方法
結論
cssファイルを読み込むにはwp_enqueue_style、
jsファイルを読み込むにはwp_enqueue_scriptを使用する。functions.phpfunction test_scripts() { wp_enqueue_style( 'main-style', get_template_directory_uri().'/css/main.css' ); // cssファイルを読み込む wp_enqueue_script( 'main-script', get_template_directory_uri().'/js/main.js'); // jsファイルを読み込む } add_action( 'wp_enqueue_scripts', 'test_scripts' );使用方法
wp_enqueue_style( $handle, $src, $deps, $ver, $in_footer ); wp_enqueue_script( $handle, $src, $deps, $ver, $in_footer );wp_enqueue_style , wp_enqueue_scriptとも関数の規則は同じです。
$handle
スタイルの名前。
ユニークでないければならない。
既存の名前を入れると、キューに追加されない。$src
スタイルシート、スクリプトファイルまでのURL。
外部ファイルを読み込むことも可能。その場合は絶対パスで入力する。ちなみに内部ファイルを読み込む際、以下の関数は頻出度が高く、覚えておくこと必須。
get_template_directory_uri(); // 親テーマのディレクトリを取得 get_stylesheet_directory_uri(); // 子テーマのディレクトリを取得 get_stylesheet_uri(); // 子テーマのstyle.cssを取得詳しくはcodexを見ると良い。
わかりやすく、書かれている。関数リファレンス/get template directory uri
関数リファレンス/get stylesheet directory uri
関数リファレンス/get stylesheet uri$deps
このスタイル・スクリプトを読み込む前に、読み込ませたいスタイル・スクリプトの$handleを配列形式で記入する。
$ver
バージョン番号を指定できる。デフォルトはfalseになっている。
$in_footer
デフォルトはfalse。
trueの場合、</body> 終了タグの前に配置。
falseの場合、<head> に置かれる。終わりに
正直、codexを見れば全て書かれている。
関数リファレンス/wp enqueue style
関数リファレンス/wp enqueue script
しかし、いちいち開くのが億劫だ。高頻出関数の引数くらい覚えておきたいという願いを込めてメモ✍️
- 投稿日:2020-02-19T01:06:17+09:00
PHP フレームワークを使わない掲示板の制作 *初心者の勉強用
目的
フレームワーク無しのPHP(PHP+Eloquent)で掲示板を作る事で、基本的な技術を確認する(主に脆弱性について)。
*今回はEloquentを使用したのですが、SQLインジェクション対策を学ぶ場合はEloquent無しの方が良いかと思います。
要件定義
入力フォームでのクロスサイトスクリプティングの対策,CSRF対策。
簡単なログイン実装し、パスワードはハッシュ化、バリデーションもする。脆弱性対策について
新規登録/ログインの処理を例にして書きたいと思います。
参考のURLは下記にまとめています。新規登録
新規登録の際は、XSS対策のエスケープ処理とパスワードのハッシュ化の処理をしてます。
対策 結果 XSS対策 (エスケープ処理 ) ○ パスワードのハッシュ化 ○ 書き方としては、
~.tpl.php
がviewで、同名の~.php
がphp部分になります(MVC構造ではないので、phpはコントローラーにまとめられていません)。*GETメソッドで参照される部分と言えるのかな?
~.php
にrequire_once
で~.tpl.php
を読み込みます。
下記の場合はsignup.php
にsignup.tpl.php
を読み込んでいます。signup.php//データベースの接続読みこんでる require_once 'bootstrap.php'; //Laravelと違って、これしないとsession使えない session_start(); //view読みこんでる require_once 'views/signup.tpl.php'; exit;バリデーションにsession機能を利用するので、
session_start()
します。
新規登録/ログイン処理をしたユーザーは、sessionに格納されます。
下記は投稿フォームのviewになります。signup.tpl.php<!DOCTYPE html> <html lang='ja'> <?php include('header.inc.php'); ?> <body> <?php include('nav.php'); ?> <div class="container"> <form action='newAccount.php' method='post'> //新規登録フォームでCSRF対策はしていないのですが、Keyとして一応。 <input type="hidden" name='user_pass' value='user_pass'> <label for='name'>Name</label><br> <input type='text' name='name'> <p></p> <label for='email'>Email</label><br> <input type='text' name='email'> <p></p> <label for='password'>Password</label><br> <input text='password' name='password'> <p></p> <button type='submit'>作成する</button> </form> <p><a href='index.php'>一覧に戻る</a></p> </div> <?php include('footer.inc.php'); ?> </body> </html>
上記の投稿フォームでPOSTされた情報は、下記のメソッドを参照してユーザー登録されます。
htmlspecialchars()
でエスケープ処理をし、password_hash()
でパスワードをハッシュ化しています。
【PHP】パスワードのハッシュ化とパスワードの認証をする方法
【PHP入門講座】 XSS攻撃への対策...エスケープ処理について
newAccount.phprequire_once 'bootstrap.php'; session_start(); if (isset($_POST["user_pass"])) { $user = new User; $name = $_REQUEST['name']; $user->name = htmlspecialchars($name, ENT_QUOTES, 'UTF-8'); $email = $_REQUEST['email']; $user->email = htmlspecialchars($email, ENT_QUOTES, 'UTF-8'); $password = $_REQUEST['password']; $password = htmlspecialchars($password, ENT_QUOTES, 'UTF-8'); $user->password = password_hash($password, PASSWORD_DEFAULT); $user->save(); $_SESSION['username'] = $_POST['name']; header('Location: index.php'); } exit;ログイン
こっちは新規登録時にハッシュ化されてデータベースに保存されたデータを、読み込む処理をしてます。
また、CSRF対策もしています。「ログイン処理にCSRF対策必要?」とまだ十分に理解していない部分もあるのですが、必要みたいです。下記参照。
ログイン時のCSRF対策は必要か
対策 結果 CSRF対策 ○ XSS対策 (エスケープ処理 ) ○ パスワードのハッシュ化 ○ signin.phprequire_once 'bootstrap.php'; session_start(); //ログインページを表示するとトークンを作成します。 $toke_byte = openssl_random_pseudo_bytes(16); $csrf_token = bin2hex($toke_byte); //作成したトークンをセッションに格納します。 $_SESSION['csrf_token'] = $csrf_token; require_once 'views/signin.tpl.php'; exit;上記で作った$csrf_tokenを下記のフォームでログイン情報と一緒にポストします。
signin.tpl.php<!DOCTYPE html> <html lang='ja'> <?php include('header.inc.php'); ?> <body> <?php include('nav.php'); ?> <div class="container"> <form action='signin_check.php' method='post'> <input type="hidden" name="csrf_token" value="<?=$csrf_token?>"> <label for='name'>Name</label><br> <input type='text' name='name'> <p></p> <label for='email'>Email</label><br> <input type='text' name='email'> <p></p> <label for='password'>Password</label><br> <input text='password' name='password'> <p></p> <button type='submit'>ログイン</button> </form> <p><a href="signup.php">Create an account</a></p> <p><a href="#">Forgot password?</a></p> <p><a href='index.php'>一覧に戻る</a></p> </div> <?php include('footer.inc.php'); ?> </body> </html>セッションに格納されたトークンとフォームからPOSTされたトークンが一致した場合のみ処理が始まります。
パスワードはハッシュ化されている為、password_verify()
を使用して読み込みます。signin-check.phprequire_once 'bootstrap.php'; session_start(); $users = User::all(); if (isset($_POST["csrf_token"]) && $_POST["csrf_token"] === $_SESSION['csrf_token']) { foreach($users as $user){ if (password_verify ($_POST['password'],$user->password)){ $_SESSION['username'] = $_POST['name']; break; } } header('Location: index.php'); } echo "不正なリクエストです"; exit;CSRF対策
CSRF対策をひよっこエンジニアがまとめてみた(随時更新予定)
サイトを安全に!PHPでcsrf対策を行う方法【初心者向け】
3分で覚え直す$_SESSIONの使い方まとめ [PHP]XSS対策
【PHP入門講座】 XSS攻撃への対策
XSSの対策をひよっこエンジニアがまとめてみたまとめ
かなり行き当たりばったりで始めた為、勉強法として半端な感じが否めないです。
反省点も洗い出して、勉強法としてブラッシュアップしたいなと思ってます。
- 投稿日:2020-02-19T01:03:23+09:00
【PHP】サスケェ!お前はオレにとっての新たな光だ!(ズンドコキヨシリスペクト)
■はじめに
かねてより作ろうと思っていたのですが、すっかり忘れていました。
ということでズンドコリスペクトでPHP上であのセリフがそろうまでループさせます。
■プログラム
<?php $words = ['サスケェ!','お前は','オレにとっての','新たな','光だ!']; $seikai = join('',$words); $totaltimes=0; do{ $str =''; for($times=1;$times<=count($words);$times++){ $str .=$words[rand(0,count($words)-1)]; } echo ++$totaltimes."回目:$str\n"; }while($str!= $seikai);■おわりに
早ければ100回くらいで揃いますが、運が悪いと5,000回以上もループしますね。
一番笑ったNGは「光だ!サスケェ!オレにとっての光だ!サスケェ!」
です。
簡単なプログラムですが、まだまだ改善の余地はありそうです。
そういえば、久しぶりにdo-while使ったな。。以上です。