Laravel6 デフォルトのメールテンプレートを編集する

こんばんは

大したことではないけど微妙にハマったので記事にします。

Laravelは会員登録やパスワードリセットなどを通知系の機能をコマンドだけで作ることができます。
php artisan make:notification クラス名とかで作れる気がする。詳しくは適当にぐぐって。

こんな感じのクラスが作られます。

<?php
namespace App\Notifications;

use Illuminate\Auth\Notifications\VerifyEmail;
use Illuminate\Notifications\Messages\MailMessage;

class TestVerifyEmail extends VerifyEmail
{
    public function toMail($notifiable)
    {
        if (static::$toMailCallback) {
            return call_user_func(static::$toMailCallback, $notifiable);
        }

        return (new MailMessage)
            ->subject(Lang::get('タイトル'))
            ->line(Lang::get('本文1行目'))
            ->action(
                Lang::get('ボタン'),
                $this->verificationUrl($notifiable)
            )
            ->line(Lang::get('本文2行目'));
    }
}

が、
このクラスで送られるメールのテンプレがvendor配下にあって編集できない!
本文とかタイトルはこのクラスで設定できるのに!
大変だ!どうしよう!しんじゃう!!

というときに
php artisan vendor:publish --tag=laravel-notifications
というコマンドを打つとあら不思議
src/resource/vendor/notifications/email.blade.php
というファイルが生成されます。すごーい。
このファイルを適当にいじればそのままメールのテンプレートになるというわけですね。
かがくのちからってすげー!

まぁちなみに、これ公式にも載ってるんですけどね。。ググって探すより公式見た方が早い。。
(これ↓は公式ではないけど公式を訳したページなのでほぼ公式だと思ってます。)

readouble.com

効率的に実装する為にどうしたらいいのか思考

こんばんは。今は夜です。こんにちは。にしやまです。

実装する時、なかなか効率的に進められないのでどうしたらできるのか考えてみます。

個人的なメモ書きなので、もし見られた方がいても参考になるかはわかりませんが、、

  • 実装すべきことの全体像が見えていない
    • システム全体の設計を把握する
  • 各所の詳細な仕様について詰められていない
    • 最初にテスト仕様書や詳細設計書などを作るべき?
  • どうやって実装していけばいいか手法を知らない(毎度ググってる)
  • 実装前に動作確認仕様書を作成して実装項目を詳細まで煮詰めた方が仕様が明文化されて実装しやすくなるのではないか?
  • 実装に取り掛かる前に、大まかな機能のみ挙げて、各機能を実装する前にその機能に関する動作確認仕様書(≒詳細設計)を作成する

apacheで.htaccessのphp_valueが使えない(解決編)

こんばんは。

にしやまです。

前回問題提起編として未解決の問題を記事にしてしまったわけですが、、

無事解決できたので進捗を報告いたします!

あらすじ

前回は
apachephpのモジュールがなくて.htaccessphp_valueがわかんないよぉ^^;」
ぼく「phpのモジュール持っとるやないかーい」
という感じでした。

原因

原因としてはphpのモジュールが読み込めていなかったことでした。
というのも、前回あげたここ

cat /etc/httpd/conf.modules.d/15-php.conf

# Cannot load both php5 and php7 modules
<IfModule !mod_php5.c>
    <IfModule prefork.c>
        LoadModule php7_module modules/libphp7.so
    </IfModule>
</IfModule>

<IfModule prefork.c>というところで弾かれてphpのモジュールがロードされていませんでした。

そもそもpreforkって何

preforkというのはapacheのMPMの種類の一つで他にはworkereventというものがあります。

MPMとは

※MPMについては僕も今日初めて存在を知っていろいろググった程度の知識しかないので引用を基本とさせていただきます。

MPM は (Multi Processing Module) の略で、Webブラウザからのリクエストを Apache がどのように並行処理するか、という部分の処理をモジュール化したものです。 Apache MPMとはなんぞやという話

下はapacheの公式

  • workerMPMは、多くのスレッドごとに複数の子プロセスを使用しています。各スレッドは一度に1つの接続を処理します。一般にワーカーは、prefork MPMよりもメモリフットプリントが小さいため、トラフィックの多いサーバーに適しています。
  • eventMPMは、ワーカーMPMのようにねじ込まれ、より多くの要求は、スレッドをサポート新しい要求上で動作するように、メインスレッドを解放するためにいくつかの処理作業をオフに渡すことで同時に提供できるように設計されています。
  • preforkMPMは、それぞれ1つのスレッドで複数の子プロセスを使用しています。各プロセスは一度に1つの接続を処理します。多くのシステムでは、preforkの速度はworkerに匹敵しますが、より多くのメモリを使用します。Preforkのスレッドレス設計は、状況によってはワーカーよりも利点があります。非スレッドセーフのサードパーティモジュールで使用でき、スレッドデバッグサポートが不十分なプラットフォームではデバッグが容易です。
    Apache MPMイベント

【図解/apache】MPM prefork/worker/event の違い

なるほど。わからん。

たぶんだけど、worker, eventはCGI版用でpreforkはモジュール版用ってことかな?
workerかeventにするならphp-fpm使っとけってことだと思う。(適当)
このへんよくわかってないからまたちゃんと調べないとだね。

あと、話それるんだけど、

  • CGI版とモジュール版
  • CGI版とCLI

みたいな表記をよく見るんだけど、これはCLI版=モジュール版ってことでいいのかな?
誰か教えてください。

なぜデフォルトの設定のままなのに弾かれたのか

httpd -V | grep MPM

Server MPM:     event

たしかにeventになっている

  • phpのデフォルトがcgi版に変わった(httpdとは別のデーモンとして動く)
  • phpcgi版はphp-fpmを使用してphpを動かす(apacheの中でphpを動かさない)

  • だからpreforkを使わない限りはapachephpのモジュールを読み込む必要がない

デフォルトでeventになっているならそりゃphpのモジュールなんて使わないんだから読み込まないもんねえ

解決策

(今回の場合は)apacheのMPMをpreforkに変更する

vi /etc/httpd/conf.modules.d/00-mpm.conf

LoadModule mpm_prefork_module modules/mod_mpm_prefork.so # コメントアウト外した
~中略~
#LoadModule mpm_event_module modules/mod_mpm_event.so # コメントアウト付けた

systemctl reload httpd

httpd -V | grep MPM

Server MPM:     prefork

こうすることで

  1. apacheのMPMがpreforkになる
  2. phpがモジュール版としてapacheに読み込まれる
  3. apachephpが組み込まれている(=モジュール版)から.htaccess内でphp_valueが使える
  4. エラー解消!!!

はい、素晴らしい。

今回はモジュール版でやるからこれだけで済んだけど、
もしcgi版でphp-fpm使うでも.htaccessとかはそのまま使うよとか言われたらどうしてたんだろ。。
MPMはeventでphp-fpm使ってなんやかんやしないといけないんだよな。。大変そう。。
いや、それはもしその時が来たら考えます。

お疲れ様でした!

ここまで読んでくれてありがとうございました!

誰かのお役に立てれば幸いです。

apacheで.htaccessのphp_valueが使えない(問題提起編)

こんにちは。こんばんは。
にしやまです。

ここ2日程は仕事で本番サーバーの構築をしていたんですが、
できたーと思ってgit cloneしたら500エラーが起きてあわわわってなってます。
ので、経緯をメモとして残そうと思います。(まだ解決してない)

以下の環境で動かしています。

  • CentOS8
  • Apache2.4.37
  • php7.3.15(cli)

ブラウザを見るとたしかにInternal Server Errorとでっかく書いてある。
なるほどね。ふむふむ。

で、apacheのエラーログを見ると

(省略)/.htaccess: Invalid command 'php_value', perhaps misspelled or defined by a module not included in the  server configuration

と書いてあった。

該当の.htaccessはこんな感じです。

# Uncomment the following to prevent the httpoxy vulnerability
# See: https://httpoxy.org/
#<IfModule mod_headers.c>
#    RequestHeader unset Proxy
#</IfModule>

# メモリ使用量の制限
php_value memory_limit -1

# POSTデータに許可される最大サイズ
php_value post_max_size 1000M

# 1つのファイルアップロードに許可される最大サイズ
php_value upload_max_filesize 1000M

<IfModule mod_rewrite.c>
    RewriteEngine on
    RewriteRule    ^(\.well-known/.*)$ $1 [L]
    Rewriterule    ^phpmyadmin/.*$ - [PT]
    RewriteRule    ^$    webroot/    [L]
    RewriteRule    (.*) webroot/$1    [L]
</IfModule>

ここのphp_valueが悪さしてるんですね。
ちなみにphp_valueを全部コメントアウトしたらシステムは表示されました。
全部お前のせいだ。

などと責めてもphp_valueちゃんは解決してくれないので、
Invalid command 'php_value'とかで適当にググってみたところ、 「phpのモジュールの読み込みが出来ていないからphp_valueが使えないんじゃねーの?」 という記事が多かったので、ちゃんとモジュールが読まれているか確認。

/etc/httpd/conf/httpd.conf 59行目

Include conf.modules.d/*.conf

ここでconf.modules.d配下の.confをすべて読み込んでいる。 なるほど。この配下にphpぽいのがあったので見てみます。

cat /etc/httpd/conf.modules.d/15-php.conf

#
# PHP is an HTML-embedded scripting language which attempts to make it
# easy for developers to write dynamically generated webpages.
#

# Cannot load both php5 and php7 modules
<IfModule !mod_php5.c>
  <IfModule prefork.c>
    LoadModule php7_module modules/libphp7.so
  </IfModule>
</IfModule>

ここでphpのモジュールを読み込んでいるのか。
中身があるのがmodules/libphp7.soとな
cat で中身を見たらバイナリファイルがばーーーーって出てきた(小並感)(小並感って初めて使った)

あれ、、phpのモジュールあんじゃんか、、?
ってところまでわかったのでこれから他の原因を探ります。。
俺たちの冒険はまだまだこれからだ!(未完)


2020/02/23追記

解決編です!
ついでに読んでってくださいなー

VirtualBoxとVagrantを使ってコマンド1つでLAMP環境を構築させる

2度目の記事です。

先日vagrantをいろいろいじってvagrant upだけでlamp環境を作れるようなvagrantを設定したので完全自己満で共有します。

なんでnginxじゃなくてapacheやねんって、僕も思いますけど弊社では今のところapacheの方が需要が高いから(というかまだnginx使う案件はやってなさそう)必然的にapacheになりました。が、nginx版も作ってみたいなとは思っています。

dockerの方が利便性は高そうなんだけど、弊社にはwin10home勢多くてdocker難民なのでvagrantにしました。

vagrantの使い方

動作手順

  1. VirtualBoxのインストール
  2. Vagrantのインストール
  3. コマンドプロンプト(win) or ターミナル(mac)を開いてvagratn -vを実行。インストールされていることを確認
  4. vagrant plugin install vagrant-vbguestを実行。共有フォルダを使うためのプラグインをインストール
  5. cd vagrant_testディレクトリのダウンロード先による)このディレクトリがあるフォルダに移動。
  6. vagrant up Vagrantfileを実行してVMを立ち上げる。(初回は時間がかかる)
  7. vagrant sshこれで立ち上げたVMに対してssh接続できる
  8. vagrant halt VMをシャットダウンする

構成

  • CenOS7
  • php7.4
    • composer
  • mysql8.0
  • apache2.4

VirtualBox, Vagrantとは

VirtualBoxはホストOSの上にゲストOSとして新たに任意のOSを立ち上げることのできる仮想化ソフト。 VagrantVirtualBoxの立ち上げ、設定などもろもろ自動化する為のツール。

その他

  • 共有フォルダはホスト側はVagrantfileのあるディレクトリでゲスト側は/var/www/html
  • DocumentRoot /var/www/html
  • 実際にコードをいじる時は共有フォルダ内をいじる
  • git cloneはローカル側の共有フォルダにする
  • vagrant ssh-configでデフォで作られるssh設定を確認できる
  • composerなどのコマンドを使うときはvagrant sshVM内に入って叩く
  • DBクライアントにはsshで接続する
  • その他vagrantコマンド
  • vagrantのバージョンが最新でないと起動しないようなので注意

Vagrantfile

Vagrant.configure("2") do |config|
  ###
  # centos7をバージョン指定してインストール
  ###
  config.vm.box = "centos/7"
  config.vm.box_version = "1905.1"

  ###
  # HTTPのポートを設定
  ###
  config.vm.network "forwarded_port", guest: 80, host: 8080

  ###
  # private_networkを指定するとホストOSからのみアクセスできる
  ###
  config.vm.network "private_network", ip: "192.168.33.10"

  ###
  # 共有フォルダの設定(VagrantFileのディレクトリと/var/www/htmlを共有)
  ###
  config.vm.synced_folder ".", "/var/www/html"

  # ※以下はシンボリックリンクを使えるようにrsyncでやってるが調整中で動くかわからないのでコメントアウト
  #  config.vm.synced_folder ".", "/var/www/html", type: "rsync",
  #    rsync__exclude: ".git/",
  #    rsync__args: ["--verbose", "--rsync-path='sudo rsync'", "--archive", "--delete", "-z", "--copy-links"]

  ###
  # ツールをvirtualboxに指定
  ###
  config.vm.provider "virtualbox" do |vb|
  ### GUIは使わない
  vb.gui = false
  ### メモリは2048
  vb.memory = "2048"
  ### シンボリックリンク作成を許可(これも調整中の為コメントアウト)
  # vb.customize ["setextradata", :id, "VBoxInternal2/SharedFoldersEnableSymlinksCreate/v-root", "1"]
  end
  
  ###
  # その他のインストール項目をinstall.shから読み込む
  ###
  config.ssh.insert_key = false
  config.vm.provision :shell, keep_color: true, path: "install.sh"
end

install.sh

# 最初にyumをupdateしておく
yum update
yum -y install wget zip unzip

# selinux無効化 ※本来二重でやる必要はないがsedコマンドが効かなかったから二重でやってる。原因はわかっていない
# ※selinux無効化は開発環境だからいいと思っているが本来はちゃんと設定などしないといけない
setenforce 0
sed -i -e "s/SELINUX=enforcing/SELINUX=disabled/g" /etc/selinux/config

# firewallのport開放
systemctl restart firewalld
firewall-cmd --permanent --zone=public --add-service=http
firewall-cmd --permanent --zone=public --add-service=https
firewall-cmd --reload

# php install 初期設定
yum -y install epel-release
rpm -Uvh http://rpms.famillecollet.com/enterprise/remi-release-7.rpm
yum -y install --enablerepo=remi,remi-php74 php php-fpm php-pdo php-mbstring php-gd php-json php-mysql php-xml php-pecl-zip

# php.iniのバックアップ timezone設定 errorを画面に表示させる設定(開発環境のみ)
cp /etc/php.ini /etc/php.ini.org
sed -i -e "s/;date\.timezone =/date\.timezone = Asia\/Tokyo/g" /etc/php.ini
sed -i -e "s/display_errors = Off/display_errors = On/g" /etc/php.ini

# composer install
EXPECTED_SIGNATURE="$(wget -q -O - https://composer.github.io/installer.sig)"
php -r "copy('https://getcomposer.org/installer', 'composer-setup.php');"
ACTUAL_SIGNATURE="$(php -r "echo hash_file('sha384', 'composer-setup.php');")"
if [ "$EXPECTED_SIGNATURE" != "$ACTUAL_SIGNATURE" ]
then
    >&2 echo 'ERROR: Invalid installer signature'
    rm composer-setup.php
    exit 1
fi
php composer-setup.php --quiet
RESULT=$?
rm composer-setup.php

# どこからでもcomposerを使えるように
mv composer.phar /usr/local/bin/composer

# Apache起動、自動起動設定
systemctl start httpd
systemctl enable httpd

# httpd.confのバックアップ .htaccessの許可
cp /etc/httpd/conf/httpd.conf /etc/httpd/conf/httpd.conf.org
sed -i -e "s/AllowOverride None/AllowOverride All/g" /etc/httpd/conf/httpd.conf
# httpd.confでphpを効かせる為の設定
sed -i -e "s/DirectoryIndex index.html/DirectoryIndex index.php index.html/g" /etc/httpd/conf/httpd.conf

# httpd.confの反映
systemctl reload httpd

# デフォで入ってるmariadbを削除してmysql8.0をinstall
yum remove mariadb-libs
rm -rf /var/lib/mysql/
yum -y install http://dev.mysql.com/get/mysql80-community-release-el7-3.noarch.rpm
yum -y install mysql-community-server mysql-community-devel mysql-utilities

# my.cnfに文字コードと認証プラグインの設定(8.0では必須)を追記
sed -i -e "s/# default-authentication-plugin=mysql_native_password/default_authentication_plugin=mysql_native_password\ncharacter-set-server = utf8/g" /etc/my.cnf

# mysqldの自動起動を有効化
systemctl enable mysqld
systemctl restart mysqld

# 変数定義 => MySQLの設定で必須
database=test_db
user=db_user
host_name=localhost
# 初期パスワードを取得する
password=`cat /var/log/mysqld.log | grep "A temporary password" | tr ' ' '\n' | tail -n1`
new_password=passwordPASSWORD@999

# mysqlの初期設定 ※mysql8ではgrantコマンドでユーザーを作れない
mysql -u root -p${password} --connect-expired-password -e "alter user root@localhost identified by '${new_password}'"
mysql -u root -p${new_password} --connect-expired-password -e "create database $database"
mysql -u root -p${new_password} --connect-expired-password -e "create user $user@$host_name identified by '$new_password'"
mysql -u root -p${new_password} --connect-expired-password -e "grant all privileges on $database.* to $user@$host_name with grant option"
mysql -u root -p${new_password} --connect-expired-password < /vagrant/db/database.sql

今のところはこれで動いているけどもしかしたら何かしらの問題があるかもしれない。

...ないといいなぁ。。

もっとこうした方がいいよとかあればコメントでもtwitterでも教えていただけるととてもうれしいです。

この間先輩からvagrantでやるのはOS立てるまでにして、あとの細かい設定はansibleでやった方がいいと教えてもらったのでansibleに作り替えるかもしれない。 軽く調べてみた感じansibleだと上のinstall.shをymlでもっと簡単に書けそうでよさげだった。

ファイル共有の問題点

ゲスト、ホスト間でファイル共有する時に

ゲスト側で共有ディレクトリ外に張ったシンボリックリンクをホスト側から参照できない

という問題が発生するんですが、 この問題のいい解決方法が思い浮かばないのでどなたかご教授いただきたいです。

これの解決のためにvagrantのファイル共有をrsyncの方式に変えようとしてるんだけど、 (rsyncならシンボリックリンクのファイルもリンクだけでなく元のファイルを共有できるぽい)

vagrantに備わってるrsyncの問題点として

  • ホスト→ゲストの一方しか同期されない
  • vagrant rsync-autoというコマンドを一度叩かないと共有が始まらない
  • 共有フォルダ間でのシンボリックリンク作成は別途設定をするもしくはコマンドプロンプトを管理者権限で実行しないと作れない

というのがあるのでなんかいい感じにできるのないかなーーーという感じです。

この問題については引き続き検討していきます。何かいいアイデアがあれば教えてくださいな。

ばーっと書いたのでかなり雑で分かりづらい文章なきがしますが、、 ここまで読んでくださってありがとうございました。

ionicの勉強会で学んだこと

 はじめて記事書きます。

以前ionicの勉強会に参加した時に会社に提出するように書いたレポートの丸コピです。

間違っている部分とかあれば教えてくださるとありがたやです。

お手柔らかにお願いします。

 

ionicとは

Web, iOS, androidのアプリを作ることができるクロスプラットフォームのUIフレームワーク

Cordova/Capacitorの上にangular/react/vueがありUIをionicが担当している。

ver4からreact, vueでも使えるようになった。(2109/12/15の最新はver.4.11.7)また、根底がCordovaからCapacitorになった。 勉強会時点ではionic/vueはまだバグもあるようでおすすめは出来なさそうだった。

※2020/02/11にionic5がリリースされたようです。https://ionicframework.com/blog/announcing-ionic-5/

 

  • Cordova/Capacitorとは何か

apache cordovaというアプリ開発用のクロスプラットフォームフレームワークで、JS, HTML, CSSを使ってアプリ開発ができる技術。アプリに対してビルドを行う時にはCordovaが使われている。

Capacitorとはionic社がCordovaの精神をそのままに最新の技術で作り直したもの。(Cordovaが作られたのが10数年前でずっと後方互換のあるバージョンアップしかしていない為、コードの中には開発当時のものもあり最新技術で作り直したいという背景があった)

現在弊社の業務として使っているionicはangular, ionicの部分だけなので、業務上Capacitorの部分を扱うことはないがアプリ用にラップするときはCordova/Capacitorの技術を使っているので、ビルドエラーの時などはCordova/Capacitorの技術も必須になる。

逆に言えば、実はCapacitorさえあればiOS, androidのアプリを作ることができる。

 

ionicはどうやってネイティブにビルドしているのか

f:id:nsnsymym:20200214230531j:plain

先述の通り実際にビルドしているのはionicではなくCordova/Capacitorであり、ionicはあくまでUI部分を担当している。

Cordova/CapacitorがWebアプリをWebView上で実行し、デバイス上のネイティブ機能(カメラ、GPSなど)を実行するためのインタ―フェイスを提供している。

 

ionicのメリット

ionicのメリットとして以下が挙げられる。

  1. (WEB開発者にとって)学習コストの低さ

  2. 大部分のソースの統一

  3. デフォルトでPWA対応

  4. コミュニティが活発

 

  • 1 について

Javascript(+ Angular, React, Vue)とHTML, CSSで開発ができるので、WEB開発者にとっては初期学習の必要なくアプリ開発を始められるので開発効率が良い。

  • 2 について

OSに依存した一部機能はそれぞれの書き方をする必要があるが、その部分を除いてソースを統一できる。

その分リソースを削減できるので開発者側としては非常に大きなメリットになる。

  • 3 について(PWA「Progressive Web Apps」とはWebサイトをネイティブアプリのように使うことができるアプリのこと)

    • インストールせずにアイコンをホーム画面に置ける。

    • プッシュ通知が利用可能となる。

    • キャッシュを残すのでオフラインでも閲覧可能。

    • 読み込み速度が格段に向上する

などの利点がある。

  • 4 について

Slackにionicのチームがあるようで、活発に活動していて質問などにいろいろ答えてくれることが多いらしい。また私の参加したconnpassによる勉強会も盛んでionicの開発者が直接色々話してくる。今回の勉強会では、本レポートに記述した内容の他に「ionicがCordovaをどうやってラップしているか」「circleCIによるionicの速度の継続的計測」などの話があった(レベルが高くて理解しきれずレポートには書けなかった。)

 

ionicのデメリット

上記の仕組みによりiOSandroidなどのOSの違いをCordova/Capacitorが吸収してくれているが、いくつかの問題もある。

  1. ネイティブ機能を使用できるかどうかはその為のプラグインが用意されているかどうかに依存している

  2. OSのバージョンアップに即時対応できない。

  3. Cordova/Capacitorが一枚かんでしまっている分どうしてもネイティブより描画速度が劣ってしまう。

 

  • 1 について

ionicではネイティブの機能を使用できるよう各機能に対応するプラグインが用意されている。

公式によるプラグインサードパーティ製のものなどもあるが、ざっと確認した限りでは基本的な機能はそろっている。https://ionicframework.com/jp/docs/native/overview(公式のプラグイン集)

が、すべてを網羅できているわけではないようなので、使いたいプラグインがなかった場合は諦めるか自作するなどの措置を取る必要がある。

 

  • 2 について

Cordova/Capacitorに依存してしまっている以上、各OSがバージョンアップしてもCordova/Capacitorが新しいバージョンに対応したものを出さない限りはバージョンアップすることができない。

Cordova/Capacitorは比較的活発に動いているコミュニティではあるが、常に即時対応できるわけではない。

また、Cordova/Capacitorのバージョンアップ対応と①のプラグインのバージョンアップ対応は別の問題であるため、両方のバージョンアップ対応を待たないといけなくなる。

 

  • 3 について

この問題は端末の性能向上とJavascriptレンダリング速度向上によりかなり改善されているので、ゲームなどのスピードを必要とするアプリでない限りはそれほど気にならないようになっている。

とはいえ、Cordova/Capacitorが一枚噛んでいるという仕組み上、描画速度がネイティブを上回ることはない。

 

まとめ

今回の勉強はレベルが高く、正直何を言っているのかわからないところもそれなりにあったが、それをきっかけとしてionicのことを良く知る機会にもなったので行って正解だった。

また、このレポートを書くにあたり、勉強会のメモだけでは情報が足りなかったのでいくつかのwebサイトからも情報を集めたが、ionicについて断片的にしかもっていなかった情報をまとめることができた。

今後も機会があれば積極的に勉強会に参加していきたい。

 

 

参考サイト

https://qiita.com/rdlabo/items/731b19cc8658df61f4a2

https://qiita.com/soarflat/items/cf5d343c75baadb461dc