PHP+SQLiteで、UPDATE文を実行すると、エラーを吐かずになぜか0 がセットされる
総括
SQLiteにおいて、SQLの書き方によっては文法エラーにならずに、 意図しない値がDBにセットされる模様。
※見解が間違っていたらごめんなさいm( "m)
背景
下記のようなPHP関数を実行する。
実行結果としては、特定IDのレコードのカラム値がUPDATEされてほしい。
function update($id, $manual_label1, $manual_label2) { var_dump($id, $manual_label1, $manual_label2); $pdo = new PDO(DB_DSN); $pdo->beginTransaction(); $sql = " update TRAINING set MANUAL_LABEL1 = :manual_label1 and MANUAL_LABEL2 = :manual_label2 where ID = :id "; $stmt = $pdo->prepare($sql); $stmt->execute( array( ":manual_label1" => $manual_label1, ":manual_label2" => $manual_label2, ":id" => $id, ) ); $pdo->commit(); return; }
問題
- 処理は成功する(エラーは出力されない)
- 意図した値でUPDATEされない。 MANUAL_LABEL1 に 0 が入る。
原因
聡明な方ならお気づきだろうが、SQLが間違っている。
andではなく , でしたと。
typoなんだ許してくれ
誤
update TRAINING set MANUAL_LABEL1 = :manual_label1 and MANUAL_LABEL2 = :manual_label2 where ID = :id
正
update TRAINING set MANUAL_LABEL1 = :manual_label1 ,MANUAL_LABEL2 = :manual_label2 where ID = :id
というよりちゃんとロールバックまでやるべきだが、 どうも例外吐いてすらいなさそう
try { $pdo = new PDO(DB_DSN); $pdo->beginTransaction(); $sql = " update TRAINING set MANUAL_LABEL1 = :manual_label1 ,MANUAL_LABEL2 = :manual_label2 where ID = :id "; $stmt = $pdo->prepare($sql); $stmt->execute( array( ":manual_label1" => $manual_label1, ":manual_label2" => $manual_label2, ":id" => $id, ) ); $pdo->commit(); } catch (PDOException $e) { $pdo->rollBack(); }
感想
SQL文法エラーで落ちてくれないですかね・・・
proxy環境下において、Python requests がグローバルIP制限に引っかったときのメモ
結論を先に書くと、「プロキシ用pacファイルまでちゃんと意識してコード書いてる?」
問題
プロキシ環境化において、Python requestsパッケージを用いて、APIを叩きたい
前提として、
- API、管理画面はグローバルIP制限を施している
- APIからレスポンスは返ってくるが、「許可されていないIPです」と出る
- ブラウザ側から管理画面には普通にアクセスできる(=インフラ的な設定・申請は問題ないはず)
- IP制限を外すと、PythonからAPIは叩ける
コード例
import requests response = requests.get('APIのURL', proxies={ 'http' : 'http://example.com' 'https' : 'http://example.com' })
GIP制限外すとつながるので、コードにも問題はなさそう。
原因
OS側でpacファイルが指定されていた。 そのpacファイル内にて、アクセス先のサイトに応じて 使用するプロキシサーバーを振り分けていることが判明。
私のコードでは、通常利用するプロキシサーバーを指定しており、 そのプロキシサーバーのIPが可変だったため、 グローバルIPの制限にひっかかっていた。
対策
方法1 PACファイル内部を見て、アクセスしようとしているAPIのURLが どのプロキシサーバーを使うかを確認し、そのプロキシサーバーを記載する
方法2 pypacというパッケージがあるので、 プロキシサーバーではなく、 PACファイルを指定→pacファイル側でプロキシサーバーを指定するようにする
使い方は下記参照
PyPAC: Proxy auto-config for Python — PyPAC 0.16.3 documentation
PACファイル確認方法の一例
win11の例
コントロールパネル→インターネットオプションとかからでも確認できると思いますよ。
総括
プロキシと言われたときには、プロキシサーバーだけではなく、 その手前の.pacファイルまで意識しましょう。
終わり
WYSIWYGエディタをWEBページに埋め込めるライブラリ比較
背景
WEBページの管理画面でHTMLを直接書かせたくないので、 WYSIWYGエディタを埋め込みたいと思った。
※WYSIWYGエディタの例(はてなブログの記事改廃画面)↓
javaScriptでいい感じのあるだろうと思ってググると案の定存在した。
調査比較
前提:
- 無料
- HTML+CSS+JSで埋め込める
三つほど見つかったので、触ってみた特徴を記載していく
一応簡単に実装もしたので、下記に配置しておく。
作成した比較サイト
ソース
gologius.github.io/test/test_WYSIWYG at master · gologius/gologius.github.io · GitHub
以下個人の感想。上記の比較サイトなども使って、自分にベストなものを選んでほしい。
trix.js
- ○ 埋め込むだけなら一番楽。 jsも書かずに済むし、input への反映も楽。すでにinputタグがあるなら、既存コードにすぐ埋め込める
- ○ undo redo ボタンがある
- × 文字サイズとか色が設定できない
- × 設定APIなどがないので、カスタマイズができない?
quill
- ○ 機能豊富。文字の色なども変えられる。画像もbase64形式で埋め込める
- ○ JSの設定変数で、表示するボタンなどを制御できる
- × カスタマイズ方法が独特。 文字サイズを任意指定できないので改造しようと思ったら、CSSの改造まで必要。
POSTでHTMLを飛ばそうとすると、下記のように少し工夫が必要になる。
詳細は上記URLの quill_test.js
参照。
var editor_input = document.getElementById(input_id); var editor_output = document.getElementById(output_id); var quill = new Quill(editor_input, baseOption); //inputにセットされている生HTMLを、変換してエディタに反映させる let initialContent = quill.clipboard.convert(editor_output.value); quill.setContents(initialContent); quill.root.innerHTML = editor_output.value; //エディタ入力時に、input に生HTMLをセットする quill.on('text-change', function(delta, oldDelta, source) { var editorHtml = editor_input.querySelector('.ql-editor').innerHTML; editor_output.value = editorHtml; });
Editor.js
- ○ 表が挿入できる
- × ブロックスタイル?と呼ばれる最新の見た目なので、使うのに慣れが必要かもしれない。通常のHTMLエディタを想定していると、現場の人に「なんじゃこれ」と言われるかも。
- × ツールバー?を固定できない
- × 行(ブロック)単位でしか、スタイル変更できない
感想
個人的なおすすめは quill。
が、ベストだとは思わない*1ので、ほかにいいのがあれば教えて。
バニラJavaScriptで頑張ってファイルアップロード処理を書く話
JSのライブラリを利用せずに、モダンなファイルアップロード処理を書こうとすると 割と色々コーディングしないといけないということが分かったのでメモ。
ネットに転がっているのは、
- D&DでUPする場合と、ファイルダイアログからUPする場合を共存させる考慮
- ファイルを追加でUPする場合の考慮
- 特定のファイルを削除する場合の考慮
- UPしたファイルを一覧で見たい場合の考慮
などが漏れているサンプルが多かったので、参考になれば幸い。
前提
- JQueryは使わない
- ライブラリは使わない(いわゆるバニラJS)Vueとか使ったほうが本当はきれいなんだけどね。
- IEなんて考慮しない
- 以下では、ある程度JavaScriptを分かっている人向けの適当な解説しかしない(メモなので)
サンプルページ
ファイルUPすると、リストでファイルが表示される。
https://gologius.github.io/test/file_upload/upload.html
ソース
下記参照。
gologius.github.io/test/file_upload at master · gologius/gologius.github.io · GitHub
ポイント1
input タグを二つ用意する。 片方がファイルを仮UPする用で、チェックが通ったものを、もう一方のinputにセットする。
HTML(抜粋
<form action="./upload.php" method="post" enctype="multipart/form-data"> <div id="dd_area" class="drop_area_off"> <div> ここにファイルをドラッグ&ドロップ or <input type="button" value="手動でファイル追加" onclick="clickUpload();" > </div> <input type="file" id="upload_files" name="upload_files[]"> <input type="file" id="tmp_files" name="tmp_files" multiple> </div> <div>アップロードしたファイル↓</div> <table class="file_list"> <tbody id="upload_files_list" > <!--実際の要素はJS側から挿入されるで--> </tbody> </table> </form>
Javascript(抜粋
function upload_files(new_files) { //変数準備 let sum_size = 0; let file_count = 0; let file_name_list = []; let work_transfer = new DataTransfer(); //通常の配列ではなく、datatransferでファイル管理する必要あり。 //現時点でUPされているファイルを走査する → 配列に格納 let now_files = document.getElementById("upload_files").files; for (var i = 0; i < now_files.length; i++) { var file = now_files[i]; work_transfer.items.add(file); sum_size += file.size; file_count += 1; file_name_list.push(file.name); } //アップロード対象のファイル群を走査 → 配列に格納 for (var i = 0; i < new_files.length; i++) { var file = new_files[i]; work_transfer.items.add(file); sum_size += file.size; file_count += 1; file_name_list.push(file.name); } //対象ファイルの走査が完了して用済みのため、tmp_filesはリセットする let elem = document.getElementById("tmp_files"); elem.files = new DataTransfer().files; //UPしてよいか判定 let errflg = false; if (sum_size > MAX_FILE_SIZE_MB * 1048576){ alert(`ファイルサイズの合計値は ${MAX_FILE_SIZE_MB}MB です`); errflg = true; } if (file_count > MAX_FILE_COUNT){ alert(`ファイルをUPできる最大個数は ${MAX_FILE_COUNT}個 です`); errflg = true; } //重複を削除したSetを生成。ファイル名が重複していると、Setの要素数がファイル数よりも減るので、それを利用する let uniqueSet = new Set(file_name_list); if (file_count != uniqueSet.size) { alert("同じファイル名が既に存在します"); errflg = true; } //UPしても問題ないと判断できれば、実際にファイルアップロードする if (errflg == false) { document.getElementById("upload_files").files = work_transfer.files; } //表示更新 update_file_list_html(); return; }
なんでこんなことをしているのかというと、 inputタグからファイルダイアログを開くと、そこにセットされていたファイルが上書きされてしまう。 上書きされてしまうので、追加でのファイルUPができないのである。
仮UPすることで、ファイル全数のサイズや個数のチェックもできるので、 仮UPしたほうがいろいろ都合もよい。
ポイント2
inputタグが持つfiles要素は、インデックスを指定して参照はできるが、 「直接の加工はできない」
できない例
let now_files = document.getElementById("upload_files").files; for (var i = 0; i < now_files.length; i++) { now_files[i] = tmp_file;// ←これはできない }
よって、datatransferを丸ごとfiles にセットしてあげる必要がある。
できる例
let now_files = document.getElementById("upload_files").files; let work_transfer = new DataTransfer(); for (var i = 0; i < now_files.length; i++) { work_transfer.items.add(tmp_file); } document.getElementById("upload_files").files = work_transfer;
特定のファイルを削除する場合には、「特定のファイルを除いた」datatransferをセットすれば、実現できる。
補足
もっとよい方法があれば教えて。
自己紹介ページの改修をした
人生のポートフォリオでも残しとこうかなと思って、HPを少し充実させることにした。
とりあえず
- 自分がいいと思った名言メモ
- デートパターンのメモ
を追加した。
進捗があれば随時追記する。
本当は会社でやってきたこととか書きたいんだけど、情報流出になるしなぁ・・・
婚活の所感(途中編)
もうすぐ30歳になるので、婚活なるものを初めてみた。
1か月やった個人的な感想などを書く。
ちなみにまだゴールはしてない。
※2023/08/15追記 別ルートで交際したので、結局入会した意味はなかった。
※2023/04/01追記 現在真剣交際してる。結局1か月半くらいしか相談所使ってない・・・
続きを読む