20200222のPHPに関する記事は10件です。

Laravelで、フォームの入力内容をコントローラで取得する

流れ

入力フォームを含む"view"
→サーバ(自分自身)にPOST
→サーバがPOSTを受け、値を受け取る

view

sample_form.blade.php
<html>
...
<form action='destination' method='post'>
    {{ csrf_field() }}
   <input id="hogehoge" name="sample_text">
   <button type="submit">完了</button>
</form>
...
</html>

form内のデータが連想配列としてPOSTされる。
inputのname属性がプロパティ名になる。

route

web.php
...
Route::post('/destination', 'FugaController@testMethod');
...

POSTを受けるとControllerへ

Controller

FugaController.php
<?php

namespace App\Http\Controllers;

use Illuminate\Http\Request;

class FugaController extends Controller
{
   public Function testMethod(Request $req)   {
      /* $req = {
         sample_text: "入力内容"
      }
      */
      $text = $req::get('sample_text');   // formのname属性で値を参照できる
      return view('welcome');
  }
}
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

Laravel 多対多関係で使っている中間テーブルの created_at, updated_at などのカラムで並べ替える

前提

userspostsfavoritesを中間テーブルとして多対多の関係になっています。

TL;DR

public function favorite_posts()
{
    return $this
        ->belongsToMany(Post::class, 'favorites', 'user_id', 'post_id')
        ->withPivot(['created_at', 'updated_at', 'id'])
        ->orderBy('pivot_updated_at', 'desc')
        ->orderBy('pivot_created_at', 'desc')
        ->orderBy('pivot_id', 'desc');
}

簡単に説明

withPivot()を使用することで中間テーブルのカラムを参照できます。
withPivot()の引数にorderby()に使用したいカラムを配列形式で指定します。
orderBy()の第1引数には'pivot_' + カラム名の形式で指定します。

確認

favorite_posts()の呼び出し元の前後に以下を追記し、実際に流れているSQLを確認します。

DB::enableQueryLog();
$user->favorite_posts;
dd(DB::getQueryLog());
array:1 [
  0 => array:3 [
    "query" => "select `posts`.*, `favorites`.`user_id` as `pivot_user_id`, `favorites`.`post_id` as `pivot_post_id`, `favorites`.`created_at` as `pivot_created_at`, `favorites`.`updated_at` as `pivot_updated_at`, `favorites`.`id` as `pivot_id` from `posts` inner join `favorites` on `posts`.`id` = `favorites`.`post_id` where `favorites`.`user_id` = ? order by `pivot_updated_at` desc, `pivot_created_at` desc, `pivot_id` desc"
    "bindings" => array:1 [
      0 => 1
    ]
    "time" => 0.37
  ]
]

中間テーブルfavoritesupdated_atcreated_atidでorderbyされているのが確認できました:clap:

参考

https://readouble.com/laravel/5.8/ja/eloquent-relationships.html
https://stackoverflow.com/questions/26551078/how-to-order-by-pivot-table-data-in-laravels-eloquent-orm/50767168

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

Laravel環境構築

composerインストール

brew install composer

PHPインストール

brew install php@7.4
echo 'export PATH="/usr/local/opt/php@7.4/bin:$PATH"' >> ~/.bash_profile
echo 'export PATH="/usr/local/opt/php@7.4/sbin:$PATH"' >> ~/.bash_profile

php -vでなぜか7.1が返ってきたのでバージョン切替

brew unlink php && brew link php@7.4
php -i | grep php.ini
php -v

これで無事7.4がインストールされた

Laravelインストール

composer global require "laravel/installer"
echo export PATH=\"$HOME/.composer/vendor/bin:\$PATH\" >> ~/.bash_profile
source ~/.bash_profile

プロジェクト作成

laravel new sampleLaravel

起動

php artisan serve

おめでとう
スクリーンショット 2020-02-22 17.04.18.png

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

Laravel/PHP で(会員登録・ログイン必要なし)画像共有SNSアプリ作りました

Laravel/PHP で(会員登録・ログイン必要なし)画像共有SNSアプリ作りました

はじめに

はじめまして

GAOGAOゲートというプログラミング合宿に参加しています。daijuです。

勉強の一環として、Laravel/PHP/JavaScriptで、非同期の画像共有SNSアプリをデプロイしました。

下記サービスURLです。詳細は後述しますが、下のURLにアクセスするだけで画像投稿できます。1枚だけでもよろしければ投稿お願いします!

https://newtreap.herokuapp.com/top?access_url=1525e4df64119a38Gname=SAMPLE

なぜ作ったのか?

もともと、昔の友達と会ったときに思い出の写真を探し出すのが難しいという不満を持っていました。
例えば、ラインだとチャットメインなのでいらない写真も混ざっていて目的の写真が見つからない!といったことありませんか?

そこで、イベント毎や仲の良い人たちでグループを立てて、画像のみ投稿して思い出を残せるアプリが作りたい(ラインの画像版みたいな感じ)と思ったのがきっかけです。

しかし、

・作成していく中で会員登録・ログインめんどくさくね?

・知らない人が開発したwebアプリに個人情報預けるのこわくね?

・結局ラインのアルバム・Googleフォト使えば良くね?

となったわけです。

ということで軌道修正して登録一切必要なしの画像共有SNSアプリを作成しました!
グループ作成時に発行されるURLを共有さえすれば画像を投稿できます。簡単です。5秒です。

ソースコードは以下にあります。プルリク受け付けています。未熟な部分多いので是非お願いします。機能はもちろん、デザインも!
https://github.com/daiju81/treap/branches

使用技術

  • Laravel6
  • PHP 7.3.11
  • JavaScript/ajax

バックエンド(一部抜粋)

public function add(Request $request)
   {

         $image = new Image();
         $image->post_id = $post->id;
         $image_path[] = $image_name[$i]->getRealPath();
         $image_file_name[] = $image_name[$i]->getClientOriginalName();
         Cloudder::upload($image_path[$i], $image_file_name[$i]);
         $publicId[$i] = Cloudder::getPublicId();
         $logoUrl = Cloudder::show($publicId[$i], [
           'width'     => 400,
           'height'    => 400
         ]);
         $logoUrl = str_replace('http', 'https', $logoUrl);
         $image->name = $logoUrl;
         $image->save();
       }
       $group_posts_images[] = Image::where('post_id', $post->id)->get();
       return redirect(route('top', [
         'access_url' => $access_url,
       ]));
   }
}

ここが核となる画像共有のプログラムですが、requestで画像情報を受け取りCloudinaryに保存しています。

フロントエンド(一部抜粋)

<div class="card-header"></div>
<div class="card-body chat-card">
  <div id="comment-data"></div>
</div>
for (var i = 0; i < data.comments.length; i++) {
   for(var a = 0; a < data.comments[i].length; a++) {
     var html = `
       <div class="media comment-visible" style="width: 100%;">
        <div class="media-body comment-body">
         <div class="row">
           <span class="comment-body-time" id="created_at">${data.comments[i][a].created_at}</span>
             </div>
             <img style="max-width: 90%;" src="${data.comments[i][a].name}" class="comment-body-content" id="comment">
          </div>
       </div>
      $("#comment-data").prepend(html);
    }
}

jsで5秒ごとに情報を受け取り更新しています。jsの知識はまだ疎いので説明が全然できません。すみません。

使い方

グループ作成し、発行されたURLをLINE等のSNSで共有するだけ!

これだけで画像を投稿できます。

まずはサンプルグループを作成したのでそこで画像投稿を試してみてください!以下URLから入れます!

https://newtreap.herokuapp.com/top?access_url=1525e4df64119a38Gname=SAMPLE

これからの展望

これからさらにアプリをブラッシュアップしていきます!

現在ハッシュタグをつけたTwitter投稿がイベント・フェス等の公式サイトや会場ビジョンで流れることがありますがこれに代わるサービスとして運用していきたいです。

プルリク受け付けているので以下から是非!
Branches · daiju81/treap · GitHub

まとめ

最初想定していたコンセプトとは少しずれましたが、ログインを削ることで少しでもユーザーが感じる壁は取り除けたかなと思っています。
これで終わりではなくどんどん改善していきます。
URL共有するだけで画像を投稿できるのでぜひ1枚だけでも投稿していただけると嬉しいです。

参考サイト(こちらを参考に作成しました。ありがとうございます)

https://qiita.com/Alesion30/items/dddb3f162e60b16fdc6d

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

[Laravel]データベースを操作したい時のメモ?

Laravelでデータベースを操作したい時のメモ

データを挿入する

route.php
Route::get('/insert', function() {
DB::insert('insert into posts(title, content) value(?, ?)', ['PHP with Laravel', 'Laravel is the best thing...']);
});

データを取り出す

route.php
Route::get('/read', function() {
$results = DB::select('select * from posts where id = ?', [1]);

return $results;
}

データの更新

route.php
Route::get('/update', function() {
$update = DB::update('update posts set title = "update title" where id = ?', [1]);
return $update;
});

データの削除

route.php
Route::get('/delete', function() {
$delete = DB::delete('delete from posts where id = ?', [1]);
return $delete;
}

Eloquent ORMデータの操作

データベーステーブルを操作するめに関連するモデルを作成する

php artisan make:model モデル名(Post)
モデル作成時にデータベースマイグレーションも作成する場合には-mオプションをつける
php artisan make:model Post --migration or php artisan make:model Post --m

Post.php
class Post extends Model
{

protected $table = 'posts'; //テーブル名
//テーブルを指定しない場合はクラス名を複数形の「スネークケース」にしたものがテーブルとして使用される。

protected $primaryKey = 'post_id'; 
//テーブルのキーをオーバーライド。指定しない場合はidが想定される

}

Eloquentでデータを取得する

route.php
use App\Post;

Route::get('/read', function() {
$posts = Post::all(); //全て取得
$post = Post::find(1)->get(); //id[1]を取得
}

特定のデータを更新する

routs.php
Route::get('basicinsert', function() {
$post = Post::find(2); //id(2)を書き換え
$post->title = "NEW 2"
$post->content = "content 2"
$post->save();
});

データの作成

routes.php
Route::get('/create', function() {
Post::create([
     'title' => 'create title',
     'content' => 'crate content'
     ]);
});
//モデルで$fillabeでカラムを指定しないとエラーになる

データのアップデート

routes.php
Route::get('/update', function(){
Post::where('id', 2)->where('is_admin', 0)
                    ->update(['title' => 'update title',
                              'content' => 'update content'
                              ]);
});

データの削除

route.php
Route::get('/delete', function() {
$post = Post::find(2);
$post->delete();

データの削除(2)

route.php
Route::get('/delete', function() {
Post::destroy(2);
//直接idを指定して削除

Post::destroy([4, 5]);
//複数id指定して削除

データの削除(ソフトデリート/論理削除)

データ復元可能なゴミ箱に入ってる状態にするソフトデリート。この場合モデルからソフトデリートされてもデータベースのレコードからデータは削除されない。代わりにそのモデルにdeleted_at属性がセットされてデータベースへ書き戻される。

モデルの設定

Post.php
namespace App;

use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\SoftDeletes; //追加

class Post extends Model
{
  use SoftDeletes;

  protected $dates = ['deleted_at']; //削除された日付をタイムスタンプとして扱う


  protected $fillable = [
  'title',
  'contetn'
  ];

}

カラムを追加したいテーブルを作成する
php artisan make:migration add_deleted_at_column_to_posts_tables --table=posts

作成されたマイグレーションファイルの設定

public function up()
{
   Schema::table('posts', function (Blueprint $table) {
       $table->softDeletes();  //追加
    };
}

public function down()
{
   Schema::table('posts', function (Blueprint $table) {
       $table->dropColumn('deleted_at'); //ロールバックする場合に備えてドロップを設定
    };
}

テーブルにカラムを追加
php artisan migrate

テーブルにdeleted_atカラムがnullで設定される
Post::find(1)->delete();
Postテーブルのid:1を削除
データはテーブルに残ったままだが、deleted_atカラムに削除された日時が入る

ソフトデリートされたデータの取得

ソフトデリートされた要素はクエリの結果から除外されます。しかし、ソフトデリートされた要素を含めたい場合は、クエリにwithTrashedメソッドを使用する。

   $post = Post::withTrashed()->where('id', 1)->get();

ソフトデリートされた要素飲みを取得したいとき

   $post = Post::onlyTrashed()->where('vote', 0)->get();  
   // ソフトデリートされたvoteカラムが0の要素を取得

ソフトデリートされた要素はゴミ箱に入った状態なので復元することもできる。
その場合は、restoreメソッドを使用する。

   $post = Post::withTrashed()->where('vote', 0)->restore();  
   // ソフトデリートされたvoteカラムが0の要素を復元

ソフトデリートされた要素を完全に削除する。
この場合はテーブルから要素も完全に削除されます。

   $post = Post::withTrashed()->where('id', 1)->forceDelete();  
   // ソフトデリートされたid:1の要素を完全に削除する

参考サイト

Laravel 5.7 Eloquent

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

【Laravel7リリース】Laravel 7 Release Notes 日本語訳

Laravel 7 Release Notes

Laravel Airlock

AirlockはSPAやモバイルアプリなどシンプル、トークンAPIを提供する機能的な認証システムです。Airlockはアプリケーションのユーザアカウントに複数のAPIトークンを生成することも可能にしました。これらのトークンはそれぞれの機能やスコップごとに機能します。

Custom Eloquent Casts

Laravel自体は豊富なキャストタイプを持っていますが、あたなはよく自らのキャストタイプを定義したいこともあるでしょうか。Laravel 7はCastsAttributesインターフェイスを実装するクラスを定義すれば、できるようになりました。

このクラスは必ずgetsetメソードを持ち、getはデータベースの生のデータをキャスト値に変換します。一方、setはキャスト値をデータベースの生のデータに変換します。例えば、jsonキャストタイプを作ってみましょう。

class Json implements CastsAttributes
{
    /**
     * Cast the given value.
     *
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @param  string  $key
     * @param  mixed  $value
     * @param  array  $attributes
     * @return array
     */
    public function get($model, $key, $value, $attributes)
    {
        return json_decode($value, true);
    }

    /**
     * Prepare the given value for storage.
     *
     * @param  \Illuminate\Database\Eloquent\Model  $model
     * @param  string  $key
     * @param  array  $value
     * @param  array  $attributes
     * @return string
     */
    public function set($model, $key, $value, $attributes)
    {
        return json_encode($value);
    }
}

カスタマイズキャストタイプを定義したら、モデルに使うことができます。

<?php

namespace App;

use App\Casts\Json;
use Illuminate\Database\Eloquent\Model;

class User extends Model
{
    /**
     * The attributes that should be cast to native types.
     *
     * @var array
     */
    protected $casts = [
        'options' => Json::class,
    ];
}

Blade Component Tags & Improvements

簡単に言うと、Bladeコンポネートはそれに対応しているクラスを持ち、それぞれのデータを受け入れることが可能になりました。全ての定義されたパブリックプロパーティーとメソードのコンポネートクラスは自動的にコンポネートビューに利用できます。コンポネート中のHTMLの属性は$attributeと言うattributeインスタンスが自動的に追加されます。
例えば、App\View\Components\Alertはこのように定義され

<?php

namespace App\View\Components;

use Illuminate\View\Component;

class Alert extends Component
{
    /**
     * The alert type.
     *
     * @var string
     */
    public $type;

    /**
     * Create the component instance.
     *
     * @param  string  $type
     * @return void
     */
    public function __construct($type)
    {
        $this->type = $type;
    }

    /**
     * Get the class for the given alert type.
     *
     * @return string
     */
    public function classForType()
    {
        return $this->type == 'danger' ? 'alert-danger' : 'alert-warning';
    }

    /**
     * Get the view / contents that represent the component.
     *
     * @return \Illuminate\View\View|string
     */
    public function render()
    {
        return view('components.alert');
    }
}

次は、コンポネートのBladeテンプレートを定義し、

<!-- /resources/views/components/alert.blade.php -->

<div class="alert {{ $classForType() }}" {{ $attributes }}>
    {{ $heading }}

    {{ $slot }}
</div>

コンポネートタグを使い、下のBladeにレンダリングされます。

<x-alert type="error" class="mb-4">
    <x-slot name="heading">
        Alert content...
    </x-slot>

    Default slot content...
</x-alert>

この例はただBlade component機能の中の一部だけで、Laravel 7は他の匿名、インラインビューコンポーネントなどたくさんの機能を改造しました。

HTTP Client

今までLaravelはGuzzle HTTP clientを使用し、HTTPリクエストなどのサービスを提供しています。Laravel 7はGuzzle一番よく使われる機能の部分を抜粋し、より使いやすいため、GuzzleのラッパーのHTTP clientを作りました。例えば、JSONデータのPostリクエストは以下のように

use Illuminate\Support\Facades\Http;

$response = Http::withHeaders([
    'X-First' => 'foo'
    'X-Second' => 'bar'
])->post('http://test.com/users', [
    'name' => 'Taylor',
]);

return $response['id'];

更に、このHTTP clientは素晴らしい、人間にわかりやすいテスト機能も搭載

Http::fake([
    // Stub a JSON response for GitHub endpoints...
    'github.com/*' => Http::response(['foo' => 'bar'], 200, ['Headers']),

    // Stub a string response for Google endpoints...
    'google.com/*' => Http::response('Hello World', 200, ['Headers']),

    // Stub a series of responses for Facebook endpoints...
    'facebook.com/*' => Http::sequence()
                            ->push('Hello World', 200)
                            ->push(['foo' => 'bar'], 200)
                            ->pushStatus(404),
]);

Fluent String Operations

LaravelのIlluminate\Support\Strクラスはもう馴染みな存在になっているでしょう。たくさんの文字列の操作に役に立つメソードがありますよね。Laravel 7はこれらのメソードに基づいて、オブジェクト指向、スムーズな文字列操作のライブラリを作成しました。Str::ofメソードを使って、Illuminate\Support\Stringableインスタンスを使用します。たくさんのメソードはメソードチェンで文字列を操作

return (string) Str::of('  Laravel Framework 6.x ')
                    ->trim()
                    ->replace('6.x', '7.x')
                    ->slug();

Route Model Binding Improvements

Key Customization

Eloquentモデルのデータはid以外のコラムを使いたいことがあるでしょうか。Laravel 7はルートパラメータにコラムを指定することを可能に

Route::get('api/posts/{post:slug}', function (App\Post $post) {
    return $post;
});

Automatic Scoping

1つのルートに多数のEloquentモデルをバンドする時に、2つ目パラメータは1つ目のパラメータに属するスコップしたい時はあるでしょう。例えば、ある特定のユーザのブログポストの場合とか

use App\Post;
use App\User;

Route::get('api/users/{user}/posts/{post:slug}', function (User $user, Post $post) {
    return $post;
});

Laravel 7はこのようにparentモデル側に定義されるコラム名をネストパラメータとして分析します。上の例では、Userモデルにpostsコラムが定義されると想定し、Postモデルデータの取得に利用します。

Multiple Mail Drivers

Laravel 7は1つのアプリに多数の"mailers"ドライバをサポートすることも可能にしました。各mailerドライバはmail設定に独自のoptiontransportを持つことや、特定のメールサービスで特定のメッセージを送信することが可能です。例えば、Postmarkにトランザクションのメールを、他の大部分のメールはAmazon SESに設定します。

デフォルトはmail設定ファイルに定義されているドライバを使用しますが、mailerメソードを使えば特定のメールドライバを指定できます。

Mail::mailer('postmark')
        ->to($request->user())
        ->send(new OrderShipped($order));

Route Caching Speed Improvements

Laravel 7は新たなメソードを利用し、route:cacheコマンドでコンパイル済みのルートキャッシュのマーチングを行っています。大規模なアプリ(800ルート以上)にて"Hello World"のベンチマークは、毎秒2倍以上のリクエストスピードに改善されました。自らの対応はいりません。

CORS Support

Laravel 7自体はBarry vd. HeuvelさんのCORSパッケージのCross-Origin Resource Sharing (CORS)OPTIONSのリクエストとレスポンスをサポートします。新たなcors設定ファイルはLaravelアプリに存在するようになります。

Query Time Casts

テーブルから生のデータをセレクトするなど、クエリ実行時にキャストを使いたい時はあるでしょう。例えば、下のクエリ

use App\Post;
use App\User;

$users = User::select([
    'users.*',
    'last_posted_at' => Post::selectRaw('MAX(created_at)')
            ->whereColumn('user_id', 'users.id')
])->get();

last_posted_atの結果は文字列になります。もしクエリ実行時はdateキャストに変換できれば便利ですね。そのため、Laravel 7にwithCastsが誕生しました。

$users = User::select([
    'users.*',
    'last_posted_at' => Post::selectRaw('MAX(created_at)')
            ->whereColumn('user_id', 'users.id')
])->withCasts([
    'last_posted_at' => 'date'
])->get();

MySQL 8+ Database Queue Improvements

前回のLaravelリリースにて、databasequeueはdeadlocksにより、商用には不十分だと考えられます。Laravel 7はMYSQL8+を使用し、データベースバックエンドqueueを改善します。FOR UPDATE SKIP LOCKEDclauseと他のSQL改善を使い、database稼働のqueueは大負荷の商用にも対応できます。

Artisan test Command

phpunitコマンドの追加として、test Artisan コマンドでもテスト実行できます。このコマンドにより、美しいコンソルUXや豊富なテスト情報が提供されます。更に、テストは初めての通らなかったテストに止まります。

php artisan test

Screenshot 2020-02-22 13.01.33.png

ちょいお試し!

vi tests/Unit/ExampleTest.php

Screenshot 2020-02-22 13.03.28.png

確かにphpunitよりわかりやすくなってるけど??
大量なテストがあれば、どうなるだろうかな??

元々phpunitに渡せるパラメータはArtisantestコマンドにも渡せます。

php artisan test --group=feature

Markdown Mail Template Improvements

デフォルトのMarkdownメールテンプレートは、Tailwind CSS カラーパレットをベースにし、更にモダンなデザインにします。もちろん、このテンプレートは自由にカスタマイズするは可能です。

Screen_Shot_2020-02-19_at_2.04.11_PM.png

Stub Customization

Artisan makeコマンドはcontrollers, jobs, migrations, testsなど様々なクラスを生成することに使われます。これらのクラスは'stub'ファイルを使用し、インプットの値を参照し、作られます。ただし、これらのクラスの構造を少し編集してmakeコマンドを使いたい事があるでしょう。Laravel 7はstub:publishを使用したら、よく使われるstubをカスタマイズすることも可能です。

php artisan stub:publish

publishedstubsフォルダはLaravelのルーツフォルダに、これらのファイルの全ての編集はmakeコマンドに反映されます。

Screenshot 2020-02-22 13.27.56.png


便利そうな機能いっぱい?

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

☀Ponanza(ポナンザ)の作成者さんが作ったお天気のアレを真似たひとり用。

Ponanza(ポナンザ)の作成者さんが作ったお天気のアレを真似たひとり使用?ものです。下記のものを作りました。開発者の場合、自分で作りたい衝動にかられると思います。まんまと駆られて作りました…なので考え方をお裾分けです。今までQiitaで公開したソースコードも必要になりますので、リンクを貼っときます。そしてメインのソースコードは下記になります(Twitterのoauthライブラリを呼び出しが必要になります。 )。

※個人の開発者様用なので位置情報は引っ張って来てません、天気の都道府県を変更されるか、Twitterの位置情報を使用し天気のAPIへ投げるなりしてください(本家はIP情報から位置情報を特定しようとしているようです)。乱暴な説明ですが駆け出しのプログラマーじゃない限りできると思います。

原文はこちら

天気のソースコードはこちら=> https://qiita.com/taoka_toshiaki/items/6818486d3e1429f050cf
月の満ち欠けのソースコードはこちら=> https://qiita.com/taoka_toshiaki/items/0b9792ebe1ce1854e355

本家はこちら
https://note.com/issei_y/n/ne128a0cf27ca
2020-02-22_1008.png

<?php
require_once ("vendor/autoload.php");
require_once ("moon.php");
require_once ("tenki.php");

use Abraham\TwitterOAuth\TwitterOAuth;


$connection = new TwitterOAuth(CONSUMER_KEY, CONSUMER_SECRET, ACCESS_TOKEN, ACCESS_TOKEN_SECRET);

$user_data=$connection->get("users/show",["screen_name"=>$user_screen_name]);
$name = $user_data->name;

date_default_timezone_set('Asia/Tokyo');
$icons = moon::$icon + tenki::$icon + array("@"=>"@");
$year = date("Y");
$mon = (int)date("m");
$day = (int)date("d");
$H = (int)date("H");

if($H>=6 and $H<=17){
    tenki::main();
    tenki::$url = "https://api.openweathermap.org/data/2.5/weather?id=".tenki::$ken->kochi["id"]."&appid=".tenki::$appid;
    tenki::api();
    $chg = tenki::$icon[str_replace("n","d",tenki::$response->weather[0]["icon"])];
}else{
    moon::main($year,$mon,$day);
    $chg = moon::icon();
}

foreach($icons as $key=>$val){
  if(preg_match("/$val/",$name)){
    $hit = $val;
  }
}
$name = str_replace("$hit",$chg,$name);
$connection->post("account/update_profile", ["name" =>$name]);
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む

URLの引数をバリデーションに使いたい(Laravel)

結論

任意のRequestクラスに以下の関数を追加する。

    /**
     * 更新、削除時に渡されるルート引数を Request Parametersに含める。
     * ただし、すでにキーが存在している場合は上書きしない。
     * @return array
     */
    public function validationData()
    {
        $params = $this->all();
        $route_params = $this->route()->parameters();

        return $params + $route_params;
    }

なんで作ろうと思ったか?

APIを作っていて、更新処理を書いている時にふと思った。

    public function update(ProjectUpdateRequest $request, $id)
    {
        $project = Project::find($id);

        // もしデータが取得できなかったら 失敗のレスポンス
        if (empty($project)) return response()->json(['result' => 'failed']);

        $project->fill($request->all());
        $project->update();
        return response()->json($project);
    }

せっかくバリデーション専用のクラスあるのに、ここでパラメータをチェックするの違和感ある。
どうにかしてRequestクラスでできないだろうか。

Requestクラス内でルートパラメータ取得

紆余曲折あったが、パラメータを取得する関数を発見したのでそれを使用。

$this->route()->parameters()

/project/{id} だったら ['id' => xxx]の形で取得できる。

Rulesでバリデーションできるようにする

Requestクラスの rules()でチェックされるデータは validationData()で取得しているので、オーバーライドしてルートパラメーターを含めるようにする。
ただし、ルートパラメータと同じ値があったときに上書きするのは望ましくないので、array_mergeは使わずに配列をマージすることにした。

        $params = $this->all();
        $route_params = $this->route()->parameters();

        return $params + $route_params;

結果

rules()で、ルートパラメータを使ってバリデーションを行えた。

とっても満足した。
効率や生産性、拡張性は見なかったことにする。

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

Ubuntu 18.04にNginx、PHP 7.4、MySQL 5.7をインストールする

目的

ローカル環境で開発していたLaravelのプロジェクトをVPSに乗せるための準備です。

OSバージョン

$ cat /etc/lsb-release
DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=18.04
DISTRIB_CODENAME=bionic
DISTRIB_DESCRIPTION="Ubuntu 18.04.4 LTS"

Nginxのインストール

$ sudo apt update
$ sudo apt install nginx

インストールが完了して、ブラウザ上からホスト名でアクセスすると以下のページが表示されると思います。

nginx画面.png

セキュリティ設定

ufwによるファイアウォール設定

Ubuntu 18.04ではファイアウォールパッケージとしてufw(Uncomplicated Firewall)がインストールされています。

SSH(22)とHTTP(80)、HTTPS(443)のNginxへの接続を許可します。

$ sudo ufw allow 'Nginx HTTP'
$ sudo ufw allow 'Nginx HTTPS'
$ sudo ufw enable

ufwコマンドに関しては下記の記事が大変参考になりました。
ufwコマンドの使い方 https://qiita.com/hana_shin/items/a630871dce209cff04f3

fail2banでアクセス制限設定

ufwと一緒にサーバへの攻撃をモニターして、保護してくれるfail2banも導入します。
こちらはインストールして、サービスを起動するだけでOKです。

$ sudo apt install fail2ban
$ sudo service fail2ban start

Nginxの設定

nginx.conf

Nginxの設定ファイルであるnginx.confを修正します。

$ sudo vim /etc/nginx/nginx.conf
  • userをwww-dataからsshのログインユーザに変更します
  • server_tokenのコメントアウトを外します
  • 必要があればclient_max_body_sizeを追加します
    これはnginxがPOSTの最大サイズを設定するための項目です(デフォルトは1MB)

fastcgi_params

NginxでPHPを動かすためにはfastcgi_paramsも修正します。
fastcgi_paramsを開いて、末尾に下記を追加します。

$ sudo vim /etc/nginx/fastcgi_params
↓追加します
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
↑追加します

追加したら構文チェックのために下記を実行します
問題なければNginxを再起動します

$ sudo nginx -t
nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
nginx: configuration file /etc/nginx/nginx.conf test is successful
$ sudo service nginx restart

PHP 7.4 のインストール

Ubuntu18.04でPHP 7.4をインストールするにはondrej/phpレポジトリを追加する必要があります

$ sudo apt install software-properties-common
$ sudo add-apt-repository ppa:ondrej/php

追加できたら一度リポジトリ一覧を更新し、モジュールと一緒にPHP 7.4をインストールします

$ sudo apt update
$ sudo apt install php7.4-fpm php7.4-common php7.4-mysql php7.4-xml php7.4-xmlrpc php7.4-curl php7.4-gd php7.4-imagick php7.4-cli php7.4-dev php7.4-imap php7.4-mbstring php7.4-opcache php7.4-soap php7.4-zip unzip -y

php 7.4およびモジュールが正しくインストールされているか下記コマンドで確認します

$ php -v
$ php-fpm7.4 -v
$ php -m

www.confを開いて、userとgroupを`www-data`からsshのログインユーザに変更します

$ sudo vim /etc/php/7.4/fpm/pool.d/www.conf
user = username 
group = username 
listen.owner = username 
listen.group = username

変更できたらphp-fpmの構文チェック、再起動を行います

$ sudo php-fpm7.4 -t
$ sudo service php7.4-fpm restart

NginxでPHPを実行する

sites-available/default

sites-available/defaultを開いて、下記のように修正します。

indexにindex.phpを追加します

index index.php index.html index.htm index.nginx-debian.html;

location ~ .php$ {の記述があれば閉じ括弧も含めてコメントアウトを外します
なければ追加してください

location ~ \.php$ {
}

括弧内に# fastcgi_pass unix:/var/run/php/php7.0-fpm.sock;のような記述があれば以下のように書き換えてコメントアウトを外します

fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;

最後に括弧内にinclude fastcgi_params;を追加します

設定例

index index.php index.html index.htm index.nginx-debian.html;

...略...

location ~ \.php$ {
       include snippets/fastcgi-php.conf;

       # With php-fpm (or other unix sockets):
       fastcgi_pass unix:/var/run/php/php7.4-fpm.sock;
       # With php-cgi (or other tcp sockets):
#      fastcgi_pass 127.0.0.1:9000;
       include fastcgi_params;
}

/var/www/htmlにindex.phpを作成します。

<?php
phpinfo();

ここまでできたらnginxを再起動させてブラウザ上からホスト名でアクセスします。

$ sudo nginx -t
$ sudo service nginx restart

phpinfo.png

親の顔より見た(?)画面が表示されましたね!

MySQL 5.7 のインストール

aptコマンドでインストールします。

$ sudo apt install mysql-server

次のコマンドでMySQLのセキュリティ設定を行います。

$ sudo mysql_secure_installation

設定方法は下記URLが参考になります。
https://weblabo.oscasierra.net/mysql-57-init-setup/

rootパスワードが設定できたらDBとユーザを作成します。
※'DATABASE_NAME'、'YOUR_NAME'、'YOUR_PASSWORD'には任意の値を適宜書き換えてください

$ mysql -u root -p
mysql> CREATE DATABASE 'DATABASE_NAME';
mysql> CREATE USER 'YOUR_NAME'@'localhost' IDENTIFIED BY 'YOUR_PASSWORD';
mysql> GRANT ALL PRIVILEGES ON DATABASE_NAME.* TO 'your_name'@'localhost';

作成できたら 設定したユーザとパスワードでMySQLサーバにアクセスできるか確認しましょう。

mysql> exit;
$ mysql -u 'YOUR_NAME' -p

最後に、index.phpを以下のように変更し、PHPでMySQL接続確認を行います。

<?php
    define('DB_HOST', 'localhost');
    define('DB_USER', 'YOUR_NAME');
    define('DB_PASSWORD', 'YOUR_PASSWORD');
    define('DB_NAME', 'DATABASE_NAME');

    // エラー表示設定:通知系以外全て表示    
    error_reporting(E_ALL & ~E_NOTICE);

    try {
        $dbh = new PDO('mysql:'.DB_NAME.';'.DB_HOST, DB_USER, DB_PASSWORD);
        print('接続しました。');
    }
    catch(PDOException $e){
        print('ERROR:'.$e->getMessage());
        exit;
    }

以下の画面が表示されたら、ミドルウェアのセットアップ完了です。お疲れ様でした:clap:

接続確認.png

参考ページ:
https://www.cloudbooklet.com/install-php-7-4-on-ubuntu/
https://stackoverflow.com/questions/25591040/nginx-serves-php-files-as-downloads-instead-of-executing-them
https://teratail.com/questions/137445

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

?月の満ち欠けPHPライブラリを書きました。ちょっと適当なアイコンで表示。

月の満ち欠けPHPライブラリを書きました、ご自由にお使いください。

ちょっと適当なアイコンで表示。
もっと正確なアイコンを取り入れたい方はご自身でご自由に変更ください。
尚、先人の知恵やネット住民達の知恵を借り出来ました、ありがとうございます。

原文はこちら

<?php
//date_default_timezone_set('Asia/Tokyo');
class moon{
    static public $icon = array(
        "0"=>'?',//朔
        "1"=>'?',//朔
        "2"=>'?',//朔
        "3"=>'?',//三日月
        "4"=>'?',//三日月
        "5"=>'?',//三日月
        "6"=>'?',//三日月
        "7"=>'?',//上弦の月',
        "8"=>'?',//上弦の月',
        "9"=>'?',//上弦の月',
        "10"=>'?',//上弦の月',
        "11"=>'?',//上弦の月',
        "12"=>'?',//十三夜月
        "13"=>'?',//十三夜月
        "14"=>'?',//十三夜月
        "15"=>"?",//望月
        "16"=>"?",//望月
        "17"=>"?",//望月
        "18"=>"?",//望月
        "19"=>"?",//寝待月
        "20"=>"?",//寝待月
        "21"=>"?",//寝待月
        "22"=>"?",//寝待月
        "23"=>'?',//下弦の月
        "24"=>'?',//下弦の月
        "25"=>'?',//下弦の月
        "26"=>"?",//二十六夜月
        "27"=>"?",//二十六夜月
        "28"=>"?",//二十六夜月
        "29"=>"?"//二十六夜月
    );
    static public $res = "0";
    static public $moon_gregorian = array(0,2,0,2,2,4,5,6,7,8,9,10);

    public function main($year=2012,$mon=12,$day=12)
    {
        static::$res = ((($year-11)%19)*11 + static::$moon_gregorian[$mon-1]+$day)%30;
    }

    public function icon(){
        return static::$icon[static::$res];
    }
}

呼び出しはこんな感じで。

    moon::main($year,$mon,$day);
    $ret = moon::icon();
  • このエントリーをはてなブックマークに追加
  • Qiitaで続きを読む