- 投稿日:2021-06-20T22:13:06+09:00
LinuxでMySQLをアップデートする方法
目次 1.MySQLのバージョン確認 2.MySQL停止 3.MySQLをアンインストールする 4.MySQLのインストール 5.終わりに 1. インストールされているMySQLのバージョン確認 cloud9は、デフォルトでMySQLがインストールされています。 バージョン確認をすると5.5系がインストールされています。 mysql --version こちらを5.7系にアップデートしていきます。 2. MySQL停止 まずはSQLを停止させます。 sudo service mysqld stop 3. MySQLをアンインストールする sudo yum -y remove mysql-config mysql55-server mysql55-libs mysql55 5.5系のSQLをアンインストールする為、上記の数値は55となっています。 4. MySQLのインストール sudo yum -y install mysql57-server mysql57 インストールしたいバージョンの数値を指定してください。 今回は5.7系をインストールする為57としています。 5. 終わりに こちらでLinuxでMysqlのアップデートが完了しましたが最後に確認をしましょう。 mysql --version 最後に 以上となります。不明点や間違っている点がありましたらコメントでお知らせください。 ありがとうございました。
- 投稿日:2021-06-20T15:54:55+09:00
[Laravel] XSS,CSRF,SQLインジェクションまとめ
はじめに 初学者が学ぶべきセキュリティ攻撃である、XSS,CSRF,SQLインジェクションについて、Laravelではどのように対策がされているのか、今一度おさらいしてみた。 検証環境 macOS Catalina ver 10.15.7 Docker ver 20.10.5 docker-compose ver 1.29.0 Laravel ver 7.30.4 MySQL ver 8.20.3 XSS(クロスサイトスクリプティング) XSSとは何か 3分でわかるXSSとCSRFの違いに書いてあるように「ユーザーがWebページにアクセスすることで不正なスクリプトが実行されてしまう脆弱性または攻撃手法」です。こちらの記事は大変わかりやすいので、ぜひ一読してください。 XSS対策のポイントは「特殊文字(< や > や " など)をエスケープする」ことです。そうすることでスクリプトではなく、単なる文字列として扱うことになるため、意図しない処理を防ぐことができます。 エスケープするためにはhtmlspecialchars関数を用います。 index.php $script = "<script>window.alert('hello world')</script>"; $script = htmlspecialchars($script,ENT_QUOTES,"UTF-8"); echo $script; // エスケープされるためalertは実行されない Laravelではどのように対策しているのか PostController.php public function create() { $script = "<script>window.alert('hello world')</script>"; return view('posts.create',compact( 'script' )); } posts/create.blade.php {{ $script }} // エスケープされるためalertは実行されない {{!! $script !!}} // ちなみに両端「!!」の場合は、alertが実行されますので注意です ドキュメントにも書いてある通り、{{ 変数 }}とすることでhtmlspecialchars関数が適用されます。 CSRF(Cross Site Request Forgeries) 脆弱なサイトと罠サイトを実際に作って学ぶ『CSRF』とその対策に書いてあるように「『罠サイト』から『標的サイト』へ HTTP リクエストを送信することで『標的サイト』を操作してしまおうという攻撃手法」です。 どのような被害が生まれるのかについて、上記記事でご確認ください。 CSRF対策のポイントは「リクエストが送信先が想定しているリクエストかどうか」です。 そのためリクエストを送信する側とそのリクエストを受信する側で合鍵のようなものを持っておけば、正しいリクエストかどうかわかるわけです。 Laravelではどのように対策しているのか input.blade.php <form action="" method="POST"> @csrf </form> この@csrfが <input type="hidden" name="_token" value="ランダムな文字列"> に置換され、このvalueを用いて正しいリクエストであるか否かを確認しているというわけですね。 まさに合鍵の役割を果たしています。 SQLインジェクション 【 Laravel 】クエリビルダ と Eloquent ORM の違いを整理!に書いてあるように、SQLインジェクションとは悪意のあるユーザーが不正なクエリ( データベースへの命令文 )を書き、データベースへアクセスしてデータの漏洩・改ざんを行う攻撃のことです。 SQLインジェクションのポイントは XSSと同様にエスケープ処理をする ユーザによる入力値を必要とするクエリはプリペアードステートメント(静的プレースホルダ)を用いる PDO::ATTR_EMULATE_PREPARES => false(Laravelではデフォルト) エミュレーションに関するまとめはPHPでデータベースに接続するときのまとめをご覧ください。 です。 プリペアードステートメント?ってなられた方は安全なSQLの呼び出し方をご覧ください。 Laravelではどのように対策しているのか 先ほど紹介させていただいた【 Laravel 】クエリビルダ と Eloquent ORM の違いを整理!に書いてあるように、SQLインジェクション対策は基本的になされているが、DB::rawなどの素のSQL文を使用するときは注意が必要です。 この点について、ドキュメントにもきちんと書かれています。 例えば以下のコードを見てみましょう。 PostController.php public function store(Request $request) { // 悪意のあるユーザによって送られてきたid $id = '5; delete from posts'; $posts = DB::table('posts')->whereRaw("id = ${id}")->get(); } こんなコードを書くことはまずありませんですが、この場合はpostsテーブルのデータが全て削除されてしまいます。 続けて、 PostController.php public function search(Request $request) { // ユーザによって検索がかけられた値 $word = "果汁100%"; // 正しくエスケープされないためエラー $results = DB::table('posts')->whereRaw("content like %${word}%")->get(); // 正しくエスケープされる $results = Post::where("content","like","%${word}%")->get(); return view('posts.search',compact( 'results' )); } このようにエスケープ処理を行っていないためSQLインジェクションの脆弱性を生む原因となってしまいます。 よってDB::rawなどの素のSQL文を使用するときは、エスケープ処理をして、しっかり対策を取らなければならないことがわかります。 rawメソッドをどうしても使わなければならない時は注意して使いましょう。 さいごに いかがだったでしょうか。 初学者が押さえておくべきセキュリティについて、Laravelではどのように対策を行っているのかを見てきましたが、普段それらを特に意識することなく、開発することができる点はやはりLaravelのすばらしい点だと思います。 一方で、「Laravelを使っていても、セキュリティ対策は不完全である」こともお分かりいただけたと思います。 Laravelでできることはフル活用して、できないことは補うようにしてセキュリティ対策をしていきたいですね。 参考サイト 3分でわかるXSSとCSRFの違い https://qiita.com/wanko5296/items/142b5b82485b0196a2da 脆弱なサイトと罠サイトを実際に作って学ぶ『CSRF』とその対策 https://www.hypertextcandy.com/csrf-hands-on-tutorial 【 Laravel 】クエリビルダ と Eloquent ORM の違いを整理! https://qiita.com/Tomo_rrow86/items/a0426ce17b978e3b05d5 PHPでデータベースに接続するときのまとめ https://qiita.com/mpyw/items/b00b72c5c95aac573b71#%E3%82%A8%E3%83%9F%E3%83%A5%E3%83%AC%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E3%81%AB%E9%96%A2%E3%81%99%E3%82%8B%E3%81%BE%E3%81%A8%E3%82%81 安全なSQLの呼び出し方 https://qiita.com/Morinikiz/items/dfdb33f25df4df0f672c 駆け出しエンジニアの皆さんに知ってほしい脆弱性のこと。 https://zenn.dev/ad5/articles/5e4e67c9663e4e0d0cb0 【Laravel】敢えて試すSQLインジェクション【仕組みを知るには実装】 https://kimamacode.com/laravel-sql-injection/ PHP+PDO+MySQLの組み合わせではSQLインジェクション攻撃で複文呼び出しが可能 https://blog.tokumaru.org/2013/12/pdo-and-mysql-allow-multiple-statements.html
- 投稿日:2021-06-20T15:17:19+09:00
AWS EC2にMySQL Serverをインストールする
はじめに 目次 MySQLをインストール MySQLへアクセスする EC2にMySQL Serverをインストール 【前提】 ・MySQL SevrerをインストールしたいEC2インスタンスにルート権限でログインしてください。 【手順】 1.MySQLリポジトリをインストールする。 yum localinstall https://dev.mysql.com/get/mysql80-community-release-el7-1.noarch.rpm -y 2.MySQL Serverをインストール。 yum install mysql-community-server -y ※サーバのインストールのため時間がかかる場合があります。 3.MySQLを起動。 systemctl start mysqld 4.サービス自動起動に設定。 EC2インスタンスが停止するとサービスも停止されるため、「EC2起動してるのにMySQL使えない!なんで?」なんてことがないように自動起動を設定します。 systemctl enable mysqld MySQLへアクセスする 1.MySQLログから初期パスワードを確認する MySQLインストール時に発行される一時パスワードを確認します。 パスワードは/var/log/mysqld.logに出力されています。 cat /var/log/mysqld.log | grep localhost 次のように出力されているはずです。 2021-06-19T10:36:06.105340Z 6 [Note] [MY-010454] [Server] A temporary password is generated for root@localhost: [パスワード] 2.MySQLにログイン mysql -u root -p ※Enter password:とでたら1で確認したパスワードを入力します。 3.初期パスワード変更 一時パスワードのままだとMySQLの操作ができないため、パスワードを変更します。 ALTER USER root@localhost IDENTIFIED BY 'パスワード'; 以降、通常のSQL操作可能です。
- 投稿日:2021-06-20T13:27:11+09:00
mysql2をbundle installできないし、brew info opensslでも解決できない
どうしたの? 状況: - Gemfileにmysql2をbundle installしようとしたところで、インストールエラーが発生。 やりたいこと: - デプロイ用のDBをPostgreSQLからMySQLに変更したく、まずはGemをインストールしたい。 環境: - Rails 6.0.2 - Ruby 2.6.5 - gem mysql2(バージョン指定なし) - AWSのEC2インスタンス内で操作(SSHを使用してインスタンスに接続) もう少し説明 mysql2 gemをGemfileに記述し、bundle installをすると以下が発生 ターミナル $ bundle Your Gemfile lists the gem devise (>= 0) more than once. You should probably keep only one of them. Remove any duplicate entries and specify the gem only once. While it's not a problem now, it could cause errors if you change the version of one of them later. Your Gemfile lists the gem omniauth-google-oauth2 (>= 0) more than once. You should probably keep only one of them. Remove any duplicate entries and specify the gem only once. While it's not a problem now, it could cause errors if you change the version of one of them later. Your Gemfile lists the gem dotenv-rails (>= 0) more than once. You should probably keep only one of them. Remove any duplicate entries and specify the gem only once. While it's not a problem now, it could cause errors if you change the version of one of them later. Fetching gem metadata from https://rubygems.org/............ Resolving dependencies... Using rake 13.0.1 Using concurrent-ruby 1.1.6 Using i18n 1.8.3 Using minitest 5.14.1 Using thread_safe 0.3.6 Using tzinfo 1.2.7 Using zeitwerk 2.3.0 Using activesupport 6.0.3.1 Using builder 3.2.4 Using erubi 1.9.0 Using mini_portile2 2.4.0 Using nokogiri 1.10.9 Using rails-dom-testing 2.0.3 Using crass 1.0.6 Using loofah 2.6.0 Using rails-html-sanitizer 1.3.0 Using actionview 6.0.3.1 Using rack 2.2.3 Using rack-test 1.1.0 Using actionpack 6.0.3.1 Using nio4r 2.5.2 Using websocket-extensions 0.1.5 Using websocket-driver 0.7.2 Using actioncable 6.0.3.1 Using globalid 0.4.2 Using activejob 6.0.3.1 Using activemodel 6.0.3.1 Using activerecord 6.0.3.1 Using mimemagic 0.3.10 Using marcel 0.3.3 Using activestorage 6.0.3.1 Using mini_mime 1.0.2 Using mail 2.7.1 Using actionmailbox 6.0.3.1 Using actionmailer 6.0.3.1 Using actiontext 6.0.3.1 Using arbre 1.2.1 Using formtastic 3.1.5 Using formtastic_i18n 0.6.0 Using has_scope 0.7.2 Using method_source 1.0.0 Using thor 1.0.1 Using railties 6.0.3.1 Using responders 3.0.1 Using inherited_resources 1.11.0 Using jquery-rails 4.4.0 Using kaminari-core 1.2.1 Using kaminari-actionview 1.2.1 Using kaminari-activerecord 1.2.1 Using kaminari 1.2.1 Using polyamorous 2.3.2 Using ransack 2.3.2 Using ffi 1.13.1 Using sassc 2.4.0 Using sprockets 4.0.2 Using sprockets-rails 3.2.1 Using tilt 2.0.10 Using sassc-rails 2.1.2 Using activeadmin 2.7.0 Using execjs 2.7.0 Using autoprefixer-rails 9.7.6 Using bcrypt 3.1.13 Using bindex 0.8.1 Using msgpack 1.3.3 Using bootsnap 1.4.6 Using popper_js 1.16.0 Using bootstrap 4.5.0 Using bundler 2.2.20 Using byebug 11.1.3 Using coderay 1.1.3 Using orm_adapter 0.5.0 Using warden 1.2.8 Using devise 4.7.2 Using dotenv 2.7.6 Using dotenv-rails 2.7.6 Using multipart-post 2.1.1 Using faraday 1.0.1 Using hashie 4.1.0 Using jbuilder 2.10.0 Using jwt 2.2.1 Using kgio 2.11.4 Using libv8 7.3.492.27.1 (x86_64-linux) Using rb-fsevent 0.10.4 Using rb-inotify 0.10.1 Using ruby_dep 1.5.0 Using listen 3.1.5 Using mini_racer 0.2.14 Using multi_json 1.14.1 Using multi_xml 0.6.0 Fetching mysql2 0.5.3 Installing mysql2 0.5.3 with native extensions Gem::Ext::BuildError: ERROR: Failed to build gem native extension. current directory: /home/tako_zhangyu/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mysql2-0.5.3/ext/mysql2 /home/tako_zhangyu/.rbenv/versions/2.6.5/bin/ruby -I /home/tako_zhangyu/.rbenv/versions/2.6.5/lib/ruby/2.6.0 -r ./siteconf20210620-23114-pervwr.rb extconf.rb --with-ldflags\=-L/usr/local/opt/openssl@1.1/lib --with-cppflags\=-I/usr/local/opt/openssl@1.1/include checking for rb_absint_size()... yes checking for rb_absint_singlebit_p()... yes checking for rb_wait_for_single_fd()... yes checking for -lmysqlclient... no ----- mysql client is missing. You may need to 'sudo apt-get install libmariadb-dev', 'sudo apt-get install libmysqlclient-dev' or 'sudo yum install mysql-devel', and try again. ----- *** extconf.rb failed *** Could not create Makefile due to some reason, probably lack of necessary libraries and/or headers. Check the mkmf.log file for more details. You may need configuration options. Provided configuration options: --with-opt-dir --without-opt-dir --with-opt-include --without-opt-include=${opt-dir}/include --with-opt-lib --without-opt-lib=${opt-dir}/lib --with-make-prog --without-make-prog --srcdir=. --curdir --ruby=/home/tako_zhangyu/.rbenv/versions/2.6.5/bin/$(RUBY_BASE_NAME) --with-mysql-dir --without-mysql-dir --with-mysql-include --without-mysql-include=${mysql-dir}/include --with-mysql-lib --without-mysql-lib=${mysql-dir}/lib --with-mysql-config --without-mysql-config --with-mysql-dir --without-mysql-dir --with-mysql-include --without-mysql-include=${mysql-dir}/include --with-mysql-lib --without-mysql-lib=${mysql-dir}/lib --with-mysqlclientlib --without-mysqlclientlib To see why this extension failed to compile, please check the mkmf.log which can be found here: /home/tako_zhangyu/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/extensions/x86_64-linux/2.6.0/mysql2-0.5.3/mkmf.log extconf failed, exit code 1 Gem files will remain installed in /home/tako_zhangyu/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mysql2-0.5.3 for inspection. Results logged to /home/tako_zhangyu/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/extensions/x86_64-linux/2.6.0/mysql2-0.5.3/gem_make.out An error occurred while installing mysql2 (0.5.3), and Bundler cannot continue. Make sure that `gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'` succeeds before bundling. In Gemfile: mysql2 立ち向かう ひとまず以下のエラー文で検索をかけてみる Make sure that `gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'` succeeds before bundling. 以下のコマンドで解決というような記事がたくさんあったが、まずssh内にbrewがなかったので実行できず ターミナル $ brew info openssl 以下コマンドでbrewをインストール ターミナル $ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" PATHを2つ通す ターミナル $ echo 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"' >> /home/tako_zhangyu/.bash_profile $ eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" Homebrewがインストールされているかを確認する意味を込めて以下を実行 ターミナル $ brew -v Homebrew 3.1.12 バージョンが表示されたのでOK 以下を実行 ターミナル $ brew info openssl openssl@1.1: stable 1.1.1k (bottled) 表示された。 別ルートの解決 ここからは多くの記事のように以下コマンドを打つなどの解決策があると思いますが ターミナル $ bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl@1.1/lib --with-cppflags=-I/usr/local/opt/openssl@1.1/include" なんやかんやで違うルートで解決したので記録します。 最初のエラー文の中にある以下の記述を実行してみる ----- mysql client is missing. You may need to 'sudo apt-get install libmariadb-dev', 'sudo apt-get install libmysqlclient-dev' or 'sudo yum install mysql-devel', and try again. ----- 結果的に有効だったのは以下コマンドのみ ターミナル $ sudo yum install mysql-devel 読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd 依存性の解決をしています 〜〜〜〜省略〜〜〜〜 インストール: mariadb-devel.x86_64 1:5.5.68-1.amzn2 依存性関連をインストールしました: mariadb-libs.x86_64 1:5.5.68-1.amzn2 完了しました! bundle installを実行 ターミナル $ bundle ~~~~省略~~~~ Bundle complete! 26 Gemfile dependencies, 109 gems now installed. Use `bundle info [gemname]` to see where a bundled gem is installed. できた
- 投稿日:2021-06-20T13:27:11+09:00
mysql2をbundle installできないし、brew info opensslも動かない
どうしたの? 状況: - Gemfileにmysql2をbundle installしようとしたところで、インストールエラーが発生。 - ググると$ brew info opensslを勧められるも動かない やりたいこと: - デプロイ用のDBをPostgreSQLからMySQLに変更したく、まずはGemをインストールしたい。 環境: - Rails 6.0.2 - Ruby 2.6.5 - gem mysql2(バージョン指定なし) - AWSのEC2インスタンス内で操作(SSHを使用してインスタンスに接続) もう少し説明 mysql2 gemをGemfileに記述し、bundle installをすると以下が発生 ターミナル $ bundle Your Gemfile lists the gem devise (>= 0) more than once. You should probably keep only one of them. Remove any duplicate entries and specify the gem only once. While it's not a problem now, it could cause errors if you change the version of one of them later. Your Gemfile lists the gem omniauth-google-oauth2 (>= 0) more than once. You should probably keep only one of them. Remove any duplicate entries and specify the gem only once. While it's not a problem now, it could cause errors if you change the version of one of them later. Your Gemfile lists the gem dotenv-rails (>= 0) more than once. You should probably keep only one of them. Remove any duplicate entries and specify the gem only once. While it's not a problem now, it could cause errors if you change the version of one of them later. Fetching gem metadata from https://rubygems.org/............ Resolving dependencies... Using rake 13.0.1 Using concurrent-ruby 1.1.6 Using i18n 1.8.3 Using minitest 5.14.1 Using thread_safe 0.3.6 Using tzinfo 1.2.7 Using zeitwerk 2.3.0 Using activesupport 6.0.3.1 Using builder 3.2.4 Using erubi 1.9.0 Using mini_portile2 2.4.0 Using nokogiri 1.10.9 Using rails-dom-testing 2.0.3 Using crass 1.0.6 Using loofah 2.6.0 Using rails-html-sanitizer 1.3.0 Using actionview 6.0.3.1 Using rack 2.2.3 Using rack-test 1.1.0 Using actionpack 6.0.3.1 Using nio4r 2.5.2 Using websocket-extensions 0.1.5 Using websocket-driver 0.7.2 Using actioncable 6.0.3.1 Using globalid 0.4.2 Using activejob 6.0.3.1 Using activemodel 6.0.3.1 Using activerecord 6.0.3.1 Using mimemagic 0.3.10 Using marcel 0.3.3 Using activestorage 6.0.3.1 Using mini_mime 1.0.2 Using mail 2.7.1 Using actionmailbox 6.0.3.1 Using actionmailer 6.0.3.1 Using actiontext 6.0.3.1 Using arbre 1.2.1 Using formtastic 3.1.5 Using formtastic_i18n 0.6.0 Using has_scope 0.7.2 Using method_source 1.0.0 Using thor 1.0.1 Using railties 6.0.3.1 Using responders 3.0.1 Using inherited_resources 1.11.0 Using jquery-rails 4.4.0 Using kaminari-core 1.2.1 Using kaminari-actionview 1.2.1 Using kaminari-activerecord 1.2.1 Using kaminari 1.2.1 Using polyamorous 2.3.2 Using ransack 2.3.2 Using ffi 1.13.1 Using sassc 2.4.0 Using sprockets 4.0.2 Using sprockets-rails 3.2.1 Using tilt 2.0.10 Using sassc-rails 2.1.2 Using activeadmin 2.7.0 Using execjs 2.7.0 Using autoprefixer-rails 9.7.6 Using bcrypt 3.1.13 Using bindex 0.8.1 Using msgpack 1.3.3 Using bootsnap 1.4.6 Using popper_js 1.16.0 Using bootstrap 4.5.0 Using bundler 2.2.20 Using byebug 11.1.3 Using coderay 1.1.3 Using orm_adapter 0.5.0 Using warden 1.2.8 Using devise 4.7.2 Using dotenv 2.7.6 Using dotenv-rails 2.7.6 Using multipart-post 2.1.1 Using faraday 1.0.1 Using hashie 4.1.0 Using jbuilder 2.10.0 Using jwt 2.2.1 Using kgio 2.11.4 Using libv8 7.3.492.27.1 (x86_64-linux) Using rb-fsevent 0.10.4 Using rb-inotify 0.10.1 Using ruby_dep 1.5.0 Using listen 3.1.5 Using mini_racer 0.2.14 Using multi_json 1.14.1 Using multi_xml 0.6.0 Fetching mysql2 0.5.3 Installing mysql2 0.5.3 with native extensions Gem::Ext::BuildError: ERROR: Failed to build gem native extension. current directory: /home/tako_zhangyu/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mysql2-0.5.3/ext/mysql2 /home/tako_zhangyu/.rbenv/versions/2.6.5/bin/ruby -I /home/tako_zhangyu/.rbenv/versions/2.6.5/lib/ruby/2.6.0 -r ./siteconf20210620-23114-pervwr.rb extconf.rb --with-ldflags\=-L/usr/local/opt/openssl@1.1/lib --with-cppflags\=-I/usr/local/opt/openssl@1.1/include checking for rb_absint_size()... yes checking for rb_absint_singlebit_p()... yes checking for rb_wait_for_single_fd()... yes checking for -lmysqlclient... no ----- mysql client is missing. You may need to 'sudo apt-get install libmariadb-dev', 'sudo apt-get install libmysqlclient-dev' or 'sudo yum install mysql-devel', and try again. ----- *** extconf.rb failed *** Could not create Makefile due to some reason, probably lack of necessary libraries and/or headers. Check the mkmf.log file for more details. You may need configuration options. Provided configuration options: --with-opt-dir --without-opt-dir --with-opt-include --without-opt-include=${opt-dir}/include --with-opt-lib --without-opt-lib=${opt-dir}/lib --with-make-prog --without-make-prog --srcdir=. --curdir --ruby=/home/tako_zhangyu/.rbenv/versions/2.6.5/bin/$(RUBY_BASE_NAME) --with-mysql-dir --without-mysql-dir --with-mysql-include --without-mysql-include=${mysql-dir}/include --with-mysql-lib --without-mysql-lib=${mysql-dir}/lib --with-mysql-config --without-mysql-config --with-mysql-dir --without-mysql-dir --with-mysql-include --without-mysql-include=${mysql-dir}/include --with-mysql-lib --without-mysql-lib=${mysql-dir}/lib --with-mysqlclientlib --without-mysqlclientlib To see why this extension failed to compile, please check the mkmf.log which can be found here: /home/tako_zhangyu/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/extensions/x86_64-linux/2.6.0/mysql2-0.5.3/mkmf.log extconf failed, exit code 1 Gem files will remain installed in /home/tako_zhangyu/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/gems/mysql2-0.5.3 for inspection. Results logged to /home/tako_zhangyu/.rbenv/versions/2.6.5/lib/ruby/gems/2.6.0/extensions/x86_64-linux/2.6.0/mysql2-0.5.3/gem_make.out An error occurred while installing mysql2 (0.5.3), and Bundler cannot continue. Make sure that `gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'` succeeds before bundling. In Gemfile: mysql2 立ち向かう ひとまず以下のエラー文で検索をかけてみる Make sure that `gem install mysql2 -v '0.5.3' --source 'https://rubygems.org/'` succeeds before bundling. 以下のコマンドで解決というような記事がたくさんあったが、まずssh内にbrewがなかったので実行できず ターミナル $ brew info openssl 以下コマンドでbrewをインストール ターミナル $ /bin/bash -c "$(curl -fsSL https://raw.githubusercontent.com/Homebrew/install/master/install.sh)" PATHを2つ通す ターミナル $ echo 'eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)"' >> /home/tako_zhangyu/.bash_profile $ eval "$(/home/linuxbrew/.linuxbrew/bin/brew shellenv)" Homebrewがインストールされているかを確認する意味を込めて以下を実行 ターミナル $ brew -v Homebrew 3.1.12 バージョンが表示されたのでOK 以下を実行 ターミナル $ brew info openssl openssl@1.1: stable 1.1.1k (bottled) 表示された。 別ルートの解決 ここからは多くの記事のように以下コマンドを打つなどの解決策があると思いますが ターミナル $ bundle config --local build.mysql2 "--with-ldflags=-L/usr/local/opt/openssl@1.1/lib --with-cppflags=-I/usr/local/opt/openssl@1.1/include" なんやかんやで違うルートで解決したので記録します。 最初のエラー文の中にある以下の記述を実行してみる ----- mysql client is missing. You may need to 'sudo apt-get install libmariadb-dev', 'sudo apt-get install libmysqlclient-dev' or 'sudo yum install mysql-devel', and try again. ----- 結果的に有効だったのは以下コマンドのみ ターミナル $ sudo yum install mysql-devel 読み込んだプラグイン:extras_suggestions, langpacks, priorities, update-motd 依存性の解決をしています 〜〜〜〜省略〜〜〜〜 インストール: mariadb-devel.x86_64 1:5.5.68-1.amzn2 依存性関連をインストールしました: mariadb-libs.x86_64 1:5.5.68-1.amzn2 完了しました! bundle installを実行 ターミナル $ bundle ~~~~省略~~~~ Bundle complete! 26 Gemfile dependencies, 109 gems now installed. Use `bundle info [gemname]` to see where a bundled gem is installed. できた
- 投稿日:2021-06-20T10:19:26+09:00
MySQLに接続できなくなったときの解決策
エラー Can't connect to MySQL server on 'localhost:3306' MySQLに接続しようとしたら上記のようなメッセージが出た。 解決策 私の場合は以下の手順を行ったら接続できるようになった。 ➀タスクマネジャーを起動する ➁「サービス」タブを選択する ➂「MySQL80」で右クリックし、「再起動」を選択する ④状態が「実行中」になったのを確認する
- 投稿日:2021-06-20T09:24:23+09:00
EmbulkでMySQLからBigQueryにデータ転送してみた。
はじめに Fluentdのバッチ版Embulkを試してみました。 大容量のデータ転送で困っていた時に役立った記憶があります。 概要としては以下のような感じ。 Embulk(エンバルク)とは、プラグ可能なマルチソースバルクデータローダーです。バルク処理に特化したプラグインベースのデータローダーで、大規模データセットのバルク転送を実施します。「データベース」「DWH」「NoSQL」「ファイル形式」「クラウドデータストア」などのデータ転送を強力にサポートします。 参考:https://www.ossnews.jp/oss_info/Embulk 基本説明も以下に載せておきます。 Embulk は、ストリーミング型ログ収集フレームワーク「fluentd」のバッチ版のようなデータ転送ツールです。特に、「1発実行」「日次バッチ処理」「定期バッチ処理」などのバルク処理用途に向いています。 転送元の「ファイル」「データベース」などからデータを吸い出し、転送先の「ストレージ」「データベース」などにロードするためのシンプルな仕組みを提供します。 プラグイン型アーキテクチャを採用しており、RubyやJavaでシンプルなコードを書くことで、さまざまな「データベース」「ファイルフォーマット」「ストレージ」に対して柔軟に対応できます。 参考:https://www.ossnews.jp/oss_info/Embulk 試してみること ローカル環境にEmbulkコンテナとMySQLコンテナを建てる。 MySQLのデータをEmbulkを使って、リモート環境のBigQueryに転送する。 リモート環境 便宜上、先に転送先のBigQueryの説明だけ書いておきます。 BigQuery テーブルはあえて用意しないで、プロジェクトとデータセットだけ作成しておきます。 ※転送先にテーブルが無い場合、embulkが自動でテーブル作成&データ投入してくれる。 ※以下写真参考。 EmbulkからBigQueryに転送するための権限を持ったサービスアカウントを作成する。 ※以下写真参考。 作成したサービスアカウントの秘密鍵を作成ダウンロードする。 ※以下写真参考。 この秘密鍵の入ったJsonファイルをEmbulk転送時に使うので、わかるところに保存しておいてください。 ローカル環境 docker-composeを使ってEmbulkとMySQLのコンテナ環境を作成する。 以下、ローカル環境全体のディレクトリ構成です。 $ tree . ├── docker-compose.yml ├── embulk │ ├── Dockerfile │ └── service_account_iam_key.json └── mysql ├── Dockerfile ├── ddl │ ├── init.sql │ ├── insert_departments.sql │ └── insert_employee.sql └── my.cnf 以下、docker-compose.yml、Embulk、MySQLの3つの環境設定について説明をしていきます。 docker-compose.yml 環境設定は以下の通り。 強いてポイントがあるとすれば、networkを作成することでホスト名でコンテナ間通信できるようにしている所くらいです。 version: '3' services: dbserver: build: ./mysql container_name: mysql_etl volumes: - ./mysql/my.cnf:/etc/mysql/my.cnf - ./mysql/ddl:/docker-entrypoint-initdb.d environment: MYSQL_DATABASE: training MYSQL_USER: fuka_user MYSQL_PASSWORD: fuka_pass MYSQL_ROOT_PASSWORD: root_pass MYSQL_PORT: 3306 ports: - 3306:3306 tty: true embulk: build: ./embulk container_name: embulk_etl volumes: - ./embulk:/home tty: true networks: etl_networks: Embulkコンテナ Dockerfile 環境設定は以下の通り。 FROM openjdk:8 # パッケージ管理システムのアップデート RUN apt-get -y update && apt-get -y upgrade # localeの設定 RUN apt-get -y install locales && \ localedef -f UTF-8 -i ja_JP ja_JP.UTF-8 ENV LANG ja_JP.UTF-8 ENV LANGUAGE ja_JP:ja ENV LC_ALL ja_JP.UTF-8 # timezone (Asia/Tokyo)の設定 ENV TZ JST-9 # vim以外にも使いそうなもの一応インストール RUN apt-get install -y vim git zip unzip less wget # MySQLコンテナ接続確認するときのためにMySQL-clientをインストール RUN apt-get install -y default-mysql-client # embulkをインストール(https://www.embulk.org/) RUN curl --create-dirs -o ~/.embulk/bin/embulk -L "https://dl.embulk.org/embulk-latest.jar" RUN chmod +x ~/.embulk/bin/embulk RUN echo 'export PATH="$HOME/.embulk/bin:$PATH"' >> ~/.bashrc RUN . ~/.bashrc # MySQL取得とBigQuery投入用のプラグインを入れておく RUN ~/.embulk/bin/embulk gem install embulk-input-mysql \ && ~/.embulk/bin/embulk gem install embulk-output-bigquery WORKDIR /root 公開鍵の配置 BigQueryにアクセスするためのservice_accountの秘密鍵を、Dockerfileと同じ階層に配置する。 名前は「service_account_iam_key.json」としました。 ├── embulk │ ├── Dockerfile │ └── service_account_iam_key.json MySQLコンテナ Dockerfile 環境設定は以下の通り。 FROM mysql:5.7 ADD ./my.cnf /etc/mysql/my.cnf RUN chmod 644 /etc/mysql/my.cnf ddl 以下の通り。 init.sql DROP SCHEMA IF EXISTS training; CREATE SCHEMA training; USE training; DROP TABLE IF EXISTS departments; CREATE TABLE departments ( department_id int primary key NOT NULL AUTO_INCREMENT, department_name varchar(20) ) ENGINE=INNODB DEFAULT CHARSET=utf8; DROP TABLE IF EXISTS employees; CREATE TABLE employees ( employee_id int primary key NOT NULL AUTO_INCREMENT, department_id int, name varchar(20), age int, CONSTRAINT fk_department_id FOREIGN KEY (department_id) REFERENCES departments (department_id) ON DELETE RESTRICT ON UPDATE RESTRICT ) ENGINE=INNODB DEFAULT CHARSET=utf8; insert_departments.sql INSERT INTO departments (department_name) VALUES ("総務"); INSERT INTO departments (department_name) VALUES ("営業"); INSERT INTO departments (department_name) VALUES ("開発"); insert_employee.sql INSERT INTO employees (department_id, name, age) VALUES (1, "佐藤", 40); INSERT INTO employees (department_id, name, age) VALUES (2, "加藤", 30); INSERT INTO employees (department_id, name, age) VALUES (3, "田中", 25); INSERT INTO employees (department_id, name, age) VALUES (3, "中村", 20); my.cnf 特別な設定はしてません。 [mysqld] character-set-server=utf8 [mysql] default-character-set=utf8 [mysqld_safe] log_error=/var/log/mysqld.log pid_file=/var/run/mysqld/mysqld.pid [client] default-character-set=utf8 動作検証 Dockerコンテナの起動 以下の手順で起動しました。 $ docker-compose build --no-cache $ docker-compose up -d $ docker exec -it embulk_etl /bin/bash ネットワーク接続チェック Embulkコンテナ→MySQLコンテナ 以下のように接続確認します。 # ping -c 3 172.28.0.3 PING 172.28.0.3 (172.28.0.3) 56(84) bytes of data. 64 bytes from 172.28.0.3: icmp_seq=1 ttl=64 time=2.49 ms 64 bytes from 172.28.0.3: icmp_seq=2 ttl=64 time=0.195 ms 64 bytes from 172.28.0.3: icmp_seq=3 ttl=64 time=0.129 ms --- 172.28.0.3 ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 15ms rtt min/avg/max/mdev = 0.129/0.939/2.493/1.099 ms # ping -c 3 mysql_etl PING mysql_etl (172.28.0.3) 56(84) bytes of data. 64 bytes from mysql_etl.mysql_docker_for_embulk_default (172.28.0.3): icmp_seq=1 ttl=64 time=0.327 ms 64 bytes from mysql_etl.mysql_docker_for_embulk_default (172.28.0.3): icmp_seq=2 ttl=64 time=0.132 ms 64 bytes from mysql_etl.mysql_docker_for_embulk_default (172.28.0.3): icmp_seq=3 ttl=64 time=0.128 ms --- mysql_etl ping statistics --- 3 packets transmitted, 3 received, 0% packet loss, time 22ms rtt min/avg/max/mdev = 0.128/0.195/0.327/0.094 ms # mysql -h mysql_etl -u fuka_user training -p Enter password: MySQL [training]> ネットワーク接続チェック Embulkコンテナ→BigQuery bqインストールします。(参考:https://cloud.google.com/sdk/docs/install#deb) # echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] https://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list # curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - # apt-get update && apt-get install google-cloud-sdk # RUN echo "deb [signed-by=/usr/share/keyrings/cloud.google.gpg] http://packages.cloud.google.com/apt cloud-sdk main" | tee -a /etc/apt/sources.list.d/google-cloud-sdk.list && curl https://packages.cloud.google.com/apt/doc/apt-key.gpg | apt-key --keyring /usr/share/keyrings/cloud.google.gpg add - && apt-get update -y && apt-get install google-cloud-sdk -y 以下のように接続確認します。 # gcloud auth login Go to the following link in your browser: https://accounts.google.com/o/oauth2/auth?response_type=省略~ Enter verification code: # bq ls 表示されれば接続確認ok embulk実行 設定ファイル準備 departmentsテーブル用 内容は以下の通りです。 # vim conf/embulk_guess_departments.yml in: type: mysql user: fuka_user password: fuka_pass host: mysql_etl database: training query: select * from departments; out: type: bigquery auth_method: json_key json_keyfile: /home/service_account_iam_key.json location: asia-northeast1 project: training-project-314502 dataset: test_embulk table: departments mode: append auto_create_table: true employeesテーブル用 内容は以下の通りです。 # vim conf/embulk_guess_employees.yml in: type: mysql user: fuka_user password: fuka_pass host: mysql_etl database: training query: select * from employees; out: type: bigquery auth_method: json_key json_keyfile: /home/service_account_iam_key.json location: asia-northeast1 project: training-project-314502 dataset: test_embulk table: employees mode: append auto_create_table: true embulk実行 departmentsテーブルの転送 実行手順は以下の通りです。 # embulk guess conf/embulk_guess_departments.yml -o conf/embulk_load_departments.yml # embulk preview -G conf/embulk_load_departments.yml ~省略~ *************************** 1 *************************** department_id ( long) : 1 department_name (string) : 総務 *************************** 2 *************************** department_id ( long) : 2 department_name (string) : 営業 *************************** 3 *************************** department_id ( long) : 3 department_name (string) : 開発 # embulk run conf/embulk_load_departments.yml employeesテーブルの転送 実行手順は以下の通りです。 # embulk guess conf/embulk_guess_employees.yml -o conf/embulk_load_employees.yml # embulk preview -G conf/embulk_load_employees.yml ~省略~ *************************** 1 *************************** employee_id ( long) : 1 department_id ( long) : 1 name (string) : 佐藤 age ( long) : 40 *************************** 2 *************************** employee_id ( long) : 2 department_id ( long) : 2 name (string) : 加藤 age ( long) : 30 *************************** 3 *************************** employee_id ( long) : 3 department_id ( long) : 3 name (string) : 田中 age ( long) : 25 *************************** 4 *************************** employee_id ( long) : 4 department_id ( long) : 3 name (string) : 中村 age ( long) : 20 # embulk run conf/embulk_load_employees.yml テーブルチェック BigQueryを確認してみるとテーブルが作成され、データが投入されていることが確認できます! コードレスでデータ転送できるので良い気がしてます・・!
- 投稿日:2021-06-20T00:01:26+09:00
データベースの全テーブル情報をPHPでCSV出力する方法
はじめに データベースにあるテーブルの情報をCSV出力するためのベストな方法を模索し、速度を計測したので記事にまとめたいと思います。 動作確認環境 PHP 8.0 Laravel 8.0 ※下位環境でも動作する場合がございます 補足 Dockerを使っていて、PHPコンテナからMySQLコンテナにコマンドが通らない場合はこちらの記事に解決法が記載されています。 Laravel(PHP)でのCSV出力方法について 主に以下の3つの方法がありました fwrite fputcsv mysqlコマンドを直接実行する fwriteとfputcsvの違いについては、こちらの記事が勉強になりました。 fwriteとfputcsvではCSV化したものをExcelで開くことがある場合は、fputcsvの方が軍配が上がる印象です。 ということで、今回はfwriteは候補から除外し、fputcsvとmysqlとでどちらが便利かを調査しました。 計測条件 1つのテーブルに一千万のレコードが入っている テーブルから指定期間のデータをCSV出力する その際出力するデータ量は約100万レコードとする 計測データ 計測に使ったソースコード $sumCount = DB::table('samples') ->where('created_at', '>=', '2026-06-22 00:00:00') ->where('created_at', '<', '2026-12-22 00:00:00') ->count(); $fetchNeedCount = (int)ceil($sumCount / 50000); for ($i = 0; $i < $fetchNeedCount; $i++) { $records = DB::table('samples') ->where('created_at', '>=', '2026-06-22 00:00:00') ->where('created_at', '<', '2026-12-22 00:00:00') ->skip($i * 50000) ->take(50000) ->get(); $stream = fopen('php://temp', 'r+b'); foreach ($records as $record) { fputcsv($stream, (array)$record); } rewind($stream); $csv = str_replace(PHP_EOL, "\r\n", stream_get_contents($stream)); $csv = mb_convert_encoding($csv, 'SJIS-win', 'UTF-8'); file_put_contents('test.csv', $csv, FILE_APPEND); } $cmd = 'mysql -B -N -u phper -h db -psecret -D local_laravel -e "SELECT * FROM samples where created_at >= \'2026-06-22 00:00:00\' and created_at < \'2026-12-22 00:00:00\'" | sed -e "s/\t/,/g" > test.csv'; exec($cmd); 結果 項目 計測時間 fputcsv 2m45s mysqlコマンド 35s なお、下記SQLを生でDBに叩いた時の計測時刻は24sでした。 SELECT * FROM samples where created_at >= '2026-06-22 00:00:00' and created_at < '2026-12-22 00:00:00'; まとめ 取得件数が少ない場合は、fputcsvとmysqlコマンドの差はそれほどなかったのですが、CSV化の対象が多くなると、fputcsv側ではメモリオーバーの発生を避けるためにクエリー発行を複数回に分ける必要が出てきたため、より時間がかかってしまう結果となりました。 なお、今回はcreated_atの型はTIMESTAMP型としましたが、時刻をUNIXタイムスタンプでも管理し、そのカラムで絞り込むというチューニング方法を用いるとさらに処理が速くなりそうです。 [追記] 実際にint型でタイムスタンプを挿入し、その値基準でしぼりこみを行うと5秒程度速くなること確認できました。 完成版コード mysqlコマンドの方がベターであることが分かったので、これを基準としてLaravelで全テーブルの情報をCSV化するコマンドを作成しましたので合わせて記載したいと思います。 <?php namespace App\Console\Commands; use Carbon\Carbon; use DB; use Illuminate\Console\Command; use Illuminate\Filesystem\Filesystem; use LogicException; /** * Class ConvertCSV. */ class ConvertCSV extends Command { /** * The filesystem instance. * * @var \Illuminate\Filesystem\Filesystem */ protected $file; /** * The name and signature of the console command. * * @var string */ protected $signature = 'convert_csv {--day=} {--period=1}'; /** * The console command description. * * @var string */ protected $description = 'convert_csv'; /** * List of connection names to be output. * * @var array */ protected $targetConnectionNames = [ 'mysql', ]; /** * FileOperation constructor. */ public function __construct( Filesystem $file ) { $this->file = $file; parent::__construct(); } /** * Execute the console command. */ public function handle(): void { [$startDate, $endDate] = $this->getStartEndTime(); $this->createDirectory(storage_path(sprintf('dump_csv/%s', $startDate))); foreach ($this->targetConnectionNames as $connectionName) { $configConnection = config('database.connections.'.$connectionName); if (empty($configConnection)) { throw new LogicException(sprintf('The target was not found:%s', $connectionName)); } $databaseName = $configConnection['database']; $username = $configConnection['username']; $password = $configConnection['password']; if (empty($databaseName) || empty($username) || empty($password)) { throw new LogicException(sprintf( 'Incorrect config settings:databaseName[%s] username[%s] password[%s]', $connectionName, $username, $password)); } $schema = DB::connection($connectionName)->getDoctrineSchemaManager(); $tableNames = $schema->listTableNames(); foreach ($tableNames as $tableName) { $mysqlBaseCommand = sprintf('mysql -B -N -u %s -h db -p%s -D %s -e', $username, $password, $databaseName); $mysqlCommand = sprintf("SELECT * FROM %s where created_at >= '%s 00:00:00' and created_at < '%s 00:00:00'", $tableName, $startDate, $endDate ); $outputFilePath = storage_path(sprintf('dump_csv/%s/%s.csv', $startDate, $tableName)); $cmd = sprintf('%s "%s" | sed -e "s/\t/,/g" > %s', $mysqlBaseCommand, $mysqlCommand, $outputFilePath); exec($cmd); $this->comment(sprintf('Completed:%s', $tableName)); } } } /** * Directory creation. * * @param string $directoryPath */ protected function createDirectory(string $directoryPath): void { if (! is_dir($directoryPath)) { $result = $this->file->makeDirectory($directoryPath, 0777, true); if (! $result) { throw new LogicException(sprintf('Directory creation failure:%s', $directoryPath)); } } } /** * Get start date and time and end date and time. */ protected function getStartEndTime(): array { $period = $this->option('period'); if ($this->option('day')) { $startDate = $this->option('day'); $endDate = Carbon::parse($startDate)->addDays($period)->format('Y-m-d'); } else { $carbon = Carbon::now(); $startDate = $carbon->format('Y-m-d'); $endDate = $carbon->addDays($period)->format('Y-m-d'); } if ($startDate > $endDate) { return [$endDate, $startDate]; } return [$startDate, $endDate]; } } 解説 mysqlのコマンド部分を変数化してより汎用性ある形にしました。 出力先は日付単位でstorage直下に出力されるようにしてあります。 Laravelではconfigでデータベース関連の値を記述する仕組みとなっているため、mysqlコマンドに使う値はそこから取得しています。 また、テーブル名一覧においてもLaravelであれば下記記事の方法で取得することが可能です。 なお、CSVファイルの先頭にヘッダーを付けたい場合はmysqlコマンドの「-N」を外すだけで大丈夫です。 勉強に使った関連記事やサイト一覧