前回はJavaScriptのライブラリ NSFW JSをつかってユーザーがアップロードした不適切な画像を検出しました。今回は実際にアップロードされた画像を削除する処理を考えます。
クライアントサイドで不適切な画像がどうかを判断する場合、どうやって不適切と判断した画像を削除するのかという問題が残ります。クライアントサイドから削除する処理は可能ではありますが、悪意あるユーザーによる不正操作も可能です。
そこで画像の判定と削除の処理はサーバーサイドでおこなうことにします。
npmで以下をインストールします($の入力は不要)。
1 2 3 |
$ npm install nsfwjs $ npm install @tensorflow/tfjs-node $ npm install axios --save |
そして以下を書きます。urlが渡されたら結果をページに出力して読み取ろうという作戦です。
index.js
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 30 31 32 33 34 35 36 37 38 |
const axios = require('axios'); const tf = require('@tensorflow/tfjs-node'); const nsfw = require('nsfwjs'); const http = require('http'); async function check(url) { const pic = await axios.get(url, { responseType: 'arraybuffer', }); const model = await nsfw.load(); const image = await tf.node.decodeImage(pic.data,3); const predictions = await model.classify(image); image.dispose(); return predictions; } const server = http.createServer(async(req, res) => { let msg = ''; try{ let arr = req.url.split('?'); let predictions = await check(arr[1]); for(let i=0; i<predictions.length; i++) msg += `${predictions[i].className}:${predictions[i].probability}\n`; } catch(e) { } res.writeHead(200, { 'Content-Type': 'text/plain; charset=utf-8' }); res.write(msg); res.end(); }); const port = 3001; server.listen(port, () => { console.log('Listening on ' + port); }); |
アプリを起動したら適当なディレクトリ(例として https://lets-csharp.com/samples/2307/nsfwjs/ )に以下をアップロードします。
.htaccess
1 2 3 4 |
<IfModule mod_rewrite.c> RewriteEngine On RewriteRule ^(.*)$ http://localhost:3001/$1 [P,L] </IfModule> |
これで https://lets-csharp.com/samples/2307/nsfwjs/?{画像のurl}でアクセスすると分析結果が表示されます。
次にJavaScript ユーザーが画像をアップロードできる15パズルをつくるに掲載されているupload.phpを以下のように変更します。
upload.php
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 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 |
<?php $temp = $_FILES['file_upload']['tmp_name']; if($temp == '') exit('ファイルが選択されていません。'); // ファイル内容をbase64でエンコード // (base64に特に意味はない。アップロードされたファイルは削除するが表示させたいだけ) $mime_type = mime_content_type($temp); $img = file_get_contents($temp); $base64 = base64_encode($img); //ファイルの保存先 $newfilename = date("Y-md-His")."-".$_FILES['file_upload']['name']; $upload = './images/'. $newfilename; if(move_uploaded_file($temp, $upload)) { error_reporting(0); // 次の行で捕まるのでPHPエラーを非表示 if (imagecreatefromstring(file_get_contents($upload)) !== false) { // アップロードされた画像ファイルの絶対urlを求める $test_url = (empty($_SERVER["HTTPS"]) ? "http://" : "https://"); $test_url .= $_SERVER["HTTP_HOST"] . dirname($_SERVER['REQUEST_URI']); $test_url .= '/images/'. $newfilename; $result = file_get_contents('https://lets-csharp.com/samples/2307/nsfwjs/?'. $test_url); $pieces = explode("\n", $result); // 画像に対する評価値 $neutral_score = 0; $porn_score = 0; $drawing_score = 0; $hentai_score = 0; $sexy_score = 0; foreach ($pieces as $piece) { $arr = explode(":", $piece); if($arr[0] == 'Neutral') $neutral_score = $arr[1]; if($arr[0] == 'Porn') $porn_score = $arr[1]; if($arr[0] == 'Drawing') $drawing_score = $arr[1]; if($arr[0] == 'Hentai') $hentai_score = $arr[1]; if($arr[0] == 'Sexy') $sexy_score = $arr[1]; } $neutral_score = round($neutral_score * 100, 1); $porn_score = round($porn_score * 100, 1); $drawing_score = round($drawing_score * 100, 1); $hentai_score = round($hentai_score * 100, 1); $sexy_score = round($sexy_score * 100, 1); unlink($upload); // ここではアップロードされたファイルはすべて削除している } else { echo "これは画像ファイルではありません"; unlink($upload); exit(0); } } else { echo "アップロード失敗"; exit(0); } ?> <!-- 確認用。画像と評価を表示する --> <!DOCTYPE html> <html lang="ja"> <head> <meta charset="UTF-8"> <title>判定結果</title> <meta http-equiv="X-UA-Compatible" content="IE=edge"> <meta name="viewport" content="width=device-width, initial-scale=1.0"> <style> td { padding: 3px 15px 3px 15px; border: 1px solid #333; } </style> </head> <body> <p><img src="data:<?php echo $mime_type; ?>;base64,<?php echo $base64; ?>" /></p> <table> <tr> <td>neutral</td> <td><?php echo $neutral_score; ?> %</td> </tr> <tr> <td>porn</td> <td><?php echo $porn_score; ?> %</td> </tr> <tr> <td>sexy</td> <td><?php echo $sexy_score; ?> %</td> </tr> <tr> <td>hentai</td> <td><?php echo $hentai_score; ?> %</td> </tr> <tr> <td>drawing</td> <td><?php echo $drawing_score; ?> %</td> </tr> </table> </body> </html> |
アップロードされた画像ファイルを評価してneutralの値が小さい場合やporn、sexy、hentaiの値が大きい場合は不適切な画像であるかもしれないと判断して実際にファイルを削除します。そうではない場合は残します。