├── .gitignore ├── MIT-LICENSE.txt ├── README.md ├── app ├── api │ ├── upload.php │ ├── verifydelete.php │ └── verifydownload.php ├── models │ ├── index.php │ └── init.php └── views │ ├── error.php │ ├── footer.php │ ├── header.php │ └── index.php ├── asset ├── css │ └── common.css └── js │ ├── common.js │ └── modal.js ├── config └── config.php ├── delete.php ├── docker-compose.yaml ├── docker ├── Dockerfile └── php │ └── php.ini ├── download.php └── index.php /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/launch.json 2 | data/* 3 | db/* 4 | -------------------------------------------------------------------------------- /MIT-LICENSE.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2017 shimosyan 2 | https://micmnis.net/ 3 | 4 | Permission is hereby granted, free of charge, to any person obtaining a 5 | copy of this software and associated documentation files (the 6 | "Software"), to deal in the Software without restriction, including 7 | without limitation the rights to use, copy, modify, merge, publish, 8 | distribute, sublicense, and/or sell copies of the Software, and to 9 | permit persons to whom the Software is furnished to do so, subject to 10 | the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be 13 | included in all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, 16 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 17 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 18 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE 19 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION 20 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION 21 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Name 2 | 3 | phpUploader 4 | 5 | ## Description 6 | 7 | サーバーに設置するだけで使える簡易PHPアップローダーです。 8 | 9 | ![スクリーンショット](https://cloud.githubusercontent.com/assets/26715606/25776917/1b5dbc02-3307-11e7-8155-e2d86c08f4a1.png) 10 | 11 | ## Requirement 12 | 13 | - PHP Version 5.3.3+ 14 | - SQLite (PHPにバンドルされたもので可、一部の環境によってはphp○-sqliteのインストールが必要です。) 15 | 16 | ## Usage 17 | 18 | ものすごい簡易なアップローダーなので以下の利用を想定しています。 19 | 20 | - 少人数且つ、不特定多数ではない利用者間でのファイルのやり取り 21 | 22 | ## Install 23 | 24 | ①下記URLからダウンロードしたファイルを任意のディレクトリに展開して下さい。 25 | 26 | 27 | 28 | **注意: v0.1及びv0.2からv1.0以降へのアップデートはできません。** 29 | 30 | ②config/config.phpを任意の値で編集して下さい。 31 | 32 | ③設置したディレクトリにapacheまたはnginxの実行権限を付与して下さい。 33 | 34 | ④この状態でサーバーに接続するとDBファイル(既定値 ./db/uploader.db)とデータ設置用のディレクトリ(既定値 ./data)が作成されます。 35 | 36 | ⑤configディレクトリとデータ設置用のディレクトリ(既定値 ./data)に.htaccessなどを用いて外部からの接続を遮断させて下さい。 37 | 38 | ⑥ファイルがアップロードできるよう、PHPとapacheまたはnginxの設定を変更してください。 39 | 40 | ## Licence 41 | 42 | Copyright (c) 2017 shimosyan 43 | Released under the MIT license 44 | 45 | -------------------------------------------------------------------------------- /app/api/upload.php: -------------------------------------------------------------------------------- 1 | 'upload_error', 'message' => $messages); 54 | //JSON形式で出力する 55 | echo json_encode( $response ); 56 | exit; 57 | } 58 | 59 | // 一時アップロード先ファイルパス 60 | $file_tmp = $_FILES['file']['tmp_name']; 61 | 62 | // ファイル名、コメントからHTMLタグを無効化 63 | $escaped_file_name = htmlspecialchars($_FILES['file']['name'], ENT_QUOTES, 'UTF-8'); 64 | $escaped_comment = htmlspecialchars($_POST['comment'], ENT_QUOTES, 'UTF-8'); 65 | 66 | //configをインクルード 67 | include('../../config/config.php'); 68 | $config = new config(); 69 | $ret = $config->index(); 70 | //配列キーが設定されている配列なら展開 71 | if (!is_null($ret)) { 72 | if(is_array($ret)){ 73 | extract($ret); 74 | } 75 | } 76 | 77 | //データのチェック 78 | //ファイル容量 79 | $filesize = filesize($file_tmp); 80 | if($filesize > $max_file_size*1024*1024){ 81 | $response = array('status' => 'filesize_over', 'filesize' => $filesize); 82 | //JSON形式で出力する 83 | echo json_encode( $response ); 84 | exit; 85 | } 86 | 87 | //ファイル拡張子 88 | $ext = substr( $escaped_file_name, strrpos( $escaped_file_name, '.') + 1); 89 | if(in_array(mb_strtolower($ext), $extension) === false){ 90 | $response = array('status' => 'extension_error', 'ext' => $ext); 91 | //JSON形式で出力する 92 | echo json_encode( $response ); 93 | exit; 94 | } 95 | 96 | //コメント文字数 97 | if(mb_strlen($escaped_comment) > $max_comment){ 98 | $response = array('status' => 'comment_error'); 99 | //JSON形式で出力する 100 | echo json_encode( $response ); 101 | exit; 102 | } 103 | 104 | //データベースの作成・オープン 105 | try{ 106 | $db = new PDO('sqlite:../../'.$db_directory.'/uploader.db'); 107 | }catch (Exception $e){ 108 | $response = array('status' => 'sqlerror'); 109 | //JSON形式で出力する 110 | echo json_encode( $response ); 111 | exit; 112 | } 113 | 114 | // デフォルトのフェッチモードを連想配列形式に設定 115 | // (毎回PDO::FETCH_ASSOCを指定する必要が無くなる) 116 | $db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); 117 | 118 | 119 | // ファイル件数を調べて設定値より多ければ一番古いものを削除 120 | $fileCount = $db->prepare("SELECT count(id) as count , min(id) as min FROM uploaded"); 121 | $fileCount->execute(); 122 | $countResult = $fileCount->fetchAll(); 123 | 124 | $count = $countResult[0]['count']; 125 | $min_id = $countResult[0]['min']; 126 | 127 | if($count >= $save_max_files){ 128 | $sql = $db->prepare("DELETE FROM uploaded WHERE id = :id"); 129 | $sql->bindValue(':id', $min_id); //ID 130 | if (! $sql->execute()) { 131 | // 削除を実施 132 | } 133 | } 134 | 135 | 136 | // ファイルの登録・ディレクトリに保存 137 | 138 | $sql = $db->prepare("INSERT INTO uploaded(origin_file_name, comment, size, count, input_date, dl_key, del_key) " . 139 | "VALUES (:origin_file_name, :comment, :size, :count, :input_date, :dl_key, :del_key)"); 140 | 141 | $arg = array(':origin_file_name' => $escaped_file_name, 142 | ':comment' => $escaped_comment, 143 | ':size' => $filesize, 144 | ':count' => 0, 145 | ':input_date' => strtotime(date('Y/m/d H:i:s')), 146 | ':dl_key' => openssl_encrypt($_POST['dlkey'],'aes-256-ecb',$key), 147 | ':del_key' => openssl_encrypt($_POST['delkey'],'aes-256-ecb',$key) 148 | ); 149 | if (! $sql->execute($arg)) { 150 | $response = array('status' => 'sqlwrite_error'); 151 | //JSON形式で出力する 152 | echo json_encode( $response ); 153 | exit; 154 | } 155 | $id = $db->lastInsertId('id'); 156 | 157 | 158 | 159 | // 正式保存先ファイルパス 160 | if ($encrypt_filename) { 161 | $file_save = '../../'.$data_directory.'/' . 'file_'.str_replace(array('\\', '/', ':', '*', '?', '\"', '<', '>', '|'), '',openssl_encrypt($id,'aes-256-ecb',$key)).'.'.$ext; 162 | } else { 163 | $file_save = '../../'.$data_directory.'/' . 'file_'.$id.'.'.$ext; 164 | } 165 | 166 | // ファイル移動 167 | $result = @move_uploaded_file($file_tmp, $file_save); 168 | 169 | 170 | if ( $result === true ) { 171 | $response = array('status' => 'ok'); 172 | } else { 173 | $response = array('status' => 'ng'); 174 | } 175 | 176 | //JSON形式で出力する 177 | echo json_encode( $response ); 178 | ?> 179 | -------------------------------------------------------------------------------- /app/api/verifydelete.php: -------------------------------------------------------------------------------- 1 | 'ng') ); 14 | exit; 15 | } 16 | 17 | //configをインクルード 18 | include('../../config/config.php'); 19 | $config = new config(); 20 | $ret = $config->index(); 21 | //配列キーが設定されている配列なら展開 22 | if (!is_null($ret)) { 23 | if(is_array($ret)){ 24 | extract($ret); 25 | } 26 | } 27 | 28 | //データベースの作成・オープン 29 | try{ 30 | $db = new PDO('sqlite:../../'.$db_directory.'/uploader.db'); 31 | }catch (Exception $e){ 32 | $response = array('status' => 'sqlerror'); 33 | //JSON形式で出力する 34 | echo json_encode( $response ); 35 | exit; 36 | } 37 | 38 | // デフォルトのフェッチモードを連想配列形式に設定 39 | // (毎回PDO::FETCH_ASSOCを指定する必要が無くなる) 40 | $db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); 41 | 42 | 43 | // 選択 (プリペアドステートメント) 44 | $stmt = $db->prepare("SELECT * FROM uploaded WHERE id = :id"); 45 | $stmt->bindValue(':id', $id); //ID 46 | $stmt->execute(); 47 | $result = $stmt->fetchAll(); 48 | foreach($result as $s){ 49 | $filename = $s['origin_file_name']; 50 | $origin_delkey = $s['del_key']; 51 | } 52 | 53 | // マスターキーが入力されていたら認証をスキップする 54 | if($post_key !== $master){ 55 | if(openssl_encrypt($post_key,'aes-256-ecb',$key) !== $origin_delkey){ 56 | //JSON形式で出力する 57 | echo json_encode( array('status' => 'failed') ); 58 | exit; 59 | } 60 | } 61 | 62 | // DL用のトークンを生成 63 | if ( PHP_MAJOR_VERSION == '5' and PHP_MINOR_VERSION == '3') { 64 | $del_key = bin2hex(openssl_encrypt($origin_delkey,'aes-256-ecb',$key, true)); 65 | }else{ 66 | $del_key = bin2hex(openssl_encrypt($origin_delkey,'aes-256-ecb',$key, OPENSSL_RAW_DATA)); 67 | } 68 | 69 | 70 | //JSON形式で出力する 71 | echo json_encode( array('status' => 'ok', 'id' => $id, 'key' => $del_key) ); 72 | ?> 73 | -------------------------------------------------------------------------------- /app/api/verifydownload.php: -------------------------------------------------------------------------------- 1 | 'ng') ); 14 | exit; 15 | } 16 | 17 | //configをインクルード 18 | include('../../config/config.php'); 19 | $config = new config(); 20 | $ret = $config->index(); 21 | //配列キーが設定されている配列なら展開 22 | if (!is_null($ret)) { 23 | if(is_array($ret)){ 24 | extract($ret); 25 | } 26 | } 27 | 28 | //データベースの作成・オープン 29 | //データベースの作成・オープン 30 | try{ 31 | $db = new PDO('sqlite:../../'.$db_directory.'/uploader.db'); 32 | }catch (Exception $e){ 33 | $response = array('status' => 'sqlerror'); 34 | //JSON形式で出力する 35 | echo json_encode( $response ); 36 | exit; 37 | } 38 | 39 | // デフォルトのフェッチモードを連想配列形式に設定 40 | // (毎回PDO::FETCH_ASSOCを指定する必要が無くなる) 41 | $db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); 42 | 43 | 44 | // 選択 (プリペアドステートメント) 45 | $stmt = $db->prepare("SELECT * FROM uploaded WHERE id = :id"); 46 | $stmt->bindValue(':id', $id); //ID 47 | $stmt->execute(); 48 | $result = $stmt->fetchAll(); 49 | foreach($result as $s){ 50 | $filename = $s['origin_file_name']; 51 | $origin_dlkey = $s['dl_key']; 52 | } 53 | 54 | // マスターキーが入力されていたら認証をスキップする 55 | if($post_key !== $master){ 56 | if(openssl_encrypt($post_key,'aes-256-ecb',$key) !== $origin_dlkey){ 57 | //JSON形式で出力する 58 | echo json_encode( array('status' => 'failed') ); 59 | exit; 60 | } 61 | } 62 | 63 | // DL用のトークンを生成 64 | if ( PHP_MAJOR_VERSION == '5' and PHP_MINOR_VERSION == '3') { 65 | $dl_key = bin2hex(openssl_encrypt($origin_dlkey,'aes-256-ecb',$key, true)); 66 | }else{ 67 | $dl_key = bin2hex(openssl_encrypt($origin_dlkey,'aes-256-ecb',$key, OPENSSL_RAW_DATA)); 68 | } 69 | 70 | //JSON形式で出力する 71 | echo json_encode( array('status' => 'ok', 'id' => $id, 'key' => $dl_key) ); 72 | ?> 73 | -------------------------------------------------------------------------------- /app/models/index.php: -------------------------------------------------------------------------------- 1 | index(); 7 | //配列キーが設定されている配列なら展開 8 | if (!is_null($ret)) { 9 | if(is_array($ret)){ 10 | extract($ret); 11 | } 12 | } 13 | 14 | //データベースの作成・オープン 15 | try{ 16 | $db = new PDO('sqlite:'.$db_directory.'/uploader.db'); 17 | }catch (Exception $e){ 18 | $error = '500 - データベースの接続に失敗しました。'; 19 | include('./app/views/header.php'); 20 | include('./app/views/error.php'); 21 | include('./app/views/footer.php'); 22 | exit; 23 | } 24 | 25 | // デフォルトのフェッチモードを連想配列形式に設定 26 | // (毎回PDO::FETCH_ASSOCを指定する必要が無くなる) 27 | $db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); 28 | 29 | // 選択 (プリペアドステートメント) 30 | $stmt = $db->prepare("SELECT * FROM uploaded"); 31 | $stmt->execute(); 32 | $r = $stmt->fetchAll(); 33 | 34 | return array('data' => $r); 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /app/models/init.php: -------------------------------------------------------------------------------- 1 | setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); 46 | 47 | //データベース初期設定 48 | $query = " 49 | CREATE TABLE IF NOT EXISTS uploaded( 50 | id INTEGER PRIMARY KEY AUTOINCREMENT, 51 | origin_file_name text, 52 | comment text, 53 | size INTEGER, 54 | count INTEGER, 55 | input_date INTEGER, 56 | dl_key text, 57 | del_key text 58 | )"; 59 | 60 | $result = $db->exec($query); 61 | 62 | //エラーの処理 63 | if($result === false){ 64 | $error = '500 - データベースの初期化に失敗しました。'; 65 | include('./app/views/header.php'); 66 | include('./app/views/error.php'); 67 | include('./app/views/footer.php'); 68 | exit; 69 | } 70 | 71 | $db = null; 72 | -------------------------------------------------------------------------------- /app/views/error.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 | 6 |
7 |
8 |
9 | -------------------------------------------------------------------------------- /app/views/footer.php: -------------------------------------------------------------------------------- 1 | 19 | 20 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | -------------------------------------------------------------------------------- /app/views/header.php: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | <?php echo $title ?> 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 23 | 24 | 25 | -------------------------------------------------------------------------------- /app/views/index.php: -------------------------------------------------------------------------------- 1 | 2 |
3 |
4 |
5 |

ファイルを登録

6 |
7 | 8 |
9 | 10 | 11 |
12 |

MBまでのファイルがアップロードできます。
対応拡張子:

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 | 58 | 59 | 66 | 67 |
68 |
69 | 70 |
71 |
72 |

ファイル一覧

73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | '; 90 | echo ''; 91 | echo ''; 92 | echo ''; 93 | echo ''; 94 | echo ''; 95 | echo ''; 96 | echo ''; 97 | echo ''; 98 | } 99 | 100 | ?> 101 | 102 | 103 | 104 | 105 | 106 | 107 | 108 | 109 | 110 | 111 | 112 | 113 | 114 |
IDファイル名コメントサイズ日付DL数削除
'.$s['id'].''.$s['origin_file_name'].''.$s['comment'].''.round($s['size'] / (1024*1024), 1 ).'MB'.date("Y/m/d H:i:s", $s['input_date']).''.$s['count'].'[DEL]
IDファイル名コメントサイズ日付DL数削除
115 |
116 |

@shimosyan/phpUploader v (GitHub)

117 |
118 |
119 | -------------------------------------------------------------------------------- /asset/css/common.css: -------------------------------------------------------------------------------- 1 | 2 | .bg-fade{ 3 | background-color: #EEE; 4 | } 5 | 6 | .bg-white{ 7 | background-color: #FFF; 8 | } 9 | 10 | .radius{ 11 | padding: 12px; 12 | border-radius: 4px; 13 | -moz-border-radius: 4px; 14 | -webkit-border-radius: 4px; 15 | -ms-border-radius: 4px; 16 | } 17 | 18 | .box-shadow{ 19 | box-shadow:0px 2px 8px -2px #777; 20 | -moz-box-shadow:0px 2px 8px -2px #777; 21 | -webkit-box-shadow:0px 2px 8px -2px #777; 22 | -ms-box-shadow:0px 2px 8px -2px #777; 23 | } 24 | 25 | .container{ 26 | padding-top: 12px; 27 | } 28 | 29 | .row{ 30 | margin-bottom: 12px; 31 | } 32 | -------------------------------------------------------------------------------- /asset/js/common.js: -------------------------------------------------------------------------------- 1 | $(document).ready(function(){ 2 | 3 | if(document.getElementById('fileList') != null){ 4 | 5 | $.extend( $.fn.dataTable.defaults, { 6 | language: { 7 | url: 'https://cdn.datatables.net/plug-ins/9dcbecd42ad/i18n/Japanese.json' 8 | } 9 | }); 10 | 11 | $('#fileList').DataTable({ 12 | "order": [ [0, "desc"] ], 13 | "columnDefs": [ { 14 | "ordered": false, 15 | "targets": [6] 16 | } ] 17 | }); 18 | } 19 | 20 | $('input[id=lefile]').change(function() { 21 | $('#fileInput').val($(this).val().replace('C:\\fakepath\\', '')); 22 | }); 23 | }); 24 | 25 | function file_upload() 26 | { 27 | if($('#fileInput').val() == ''){ 28 | return; 29 | } 30 | 31 | $('#errorContainer').fadeOut(); 32 | $('#uploadContainer').fadeIn(); 33 | // フォームデータを取得 34 | var formdata = new FormData($('#upload').get(0)); 35 | 36 | // POSTでアップロード 37 | 38 | $.ajax({ 39 | url : './app/api/upload.php', 40 | type : 'POST', 41 | data : formdata, 42 | cache : false, 43 | contentType : false, 44 | processData : false, 45 | dataType : 'json', 46 | async: true, 47 | xhr : function(){ 48 | var XHR = $.ajaxSettings.xhr(); 49 | if(XHR.upload){ 50 | XHR.upload.addEventListener('progress',function(e){ 51 | var progre = parseInt(e.loaded/e.total*100); 52 | $('#progressBar').css({width: progre+'%'}); 53 | }, false); 54 | } 55 | return XHR; 56 | }, 57 | }) 58 | .done(function(data, textStatus, jqXHR){ 59 | //alert(data.tmp_file); 60 | switch (data.status){ 61 | case 'filesize_over': 62 | $('#errorContainer > .panel-body').text('ファイル容量が大きすぎます。'); 63 | $('#errorContainer').fadeIn(); 64 | break; 65 | case 'extension_error': 66 | $('#errorContainer > .panel-body').text('許可されていない拡張子です。拡張子:'+data.ext); 67 | $('#errorContainer').fadeIn(); 68 | break; 69 | case 'comment_error': 70 | $('#errorContainer > .panel-body').text('コメントの文字数が規定数を超えています。'); 71 | $('#errorContainer').fadeIn(); 72 | break; 73 | case 'sqlwrite_error': 74 | $('#errorContainer > .panel-body').text('データベースの書き込みに失敗しました。'); 75 | $('#errorContainer').fadeIn(); 76 | break; 77 | case 'ok': 78 | location.reload(); 79 | break; 80 | } 81 | 82 | }) 83 | .fail(function(jqXHR, textStatus, errorThrown){ 84 | $('#errorContainer > .panel-body').html('サーバーエラー
jqXHR: '+JSON.stringify(jqXHR)+'
textSattus: '+textStatus+'
errorThrown: '+errorThrown); 85 | $('#errorContainer').fadeIn(); 86 | }) 87 | .always(function( jqXHR, textStatus ) { 88 | $('#uploadContainer').hide(); 89 | }); 90 | } 91 | 92 | // DLボタンを押すと実行 93 | function dl_button(id){ 94 | // DLkey空白で投げる 95 | dl_certificat(id ,''); 96 | } 97 | 98 | function confirm_dl_button(id){ 99 | closeModal(); 100 | dl_certificat(id ,$('#confirmDlkeyInput').val()); 101 | } 102 | 103 | function dl_certificat(id, key){ 104 | var postdata ={ 105 | id: id, 106 | key: key 107 | } 108 | 109 | $.ajax({ 110 | url : './app/api/verifydownload.php', 111 | type : 'POST', 112 | data : postdata, 113 | dataType : 'json' 114 | }) 115 | .done(function(data, textStatus, jqXHR){ 116 | var html = '
'; 117 | switch (data.status){ 118 | case 'failed': 119 | openModal('okcansel', '認証が必要です', html, 'confirm_dl_button('+id+');'); 120 | break; 121 | case 'ok': 122 | location.href = './download.php?id='+data.id+'&key='+data.key; 123 | break; 124 | } 125 | 126 | }) 127 | .fail(function(jqXHR, textStatus, errorThrown){ 128 | alert(JSON.stringify(jqXHR)); 129 | }) 130 | .always(function( jqXHR, textStatus ) { 131 | }); 132 | } 133 | 134 | // DELボタンを押すと実行 135 | function del_button(id){ 136 | // DLkey空白で投げる 137 | del_certificat(id ,''); 138 | } 139 | 140 | function confirm_del_button(id){ 141 | closeModal(); 142 | del_certificat(id ,$('#confirmDelkeyInput').val()); 143 | } 144 | 145 | function del_certificat(id, key){ 146 | var postdata ={ 147 | id: id, 148 | key: key 149 | } 150 | 151 | $.ajax({ 152 | url : './app/api/verifydelete.php', 153 | type : 'POST', 154 | data : postdata, 155 | dataType : 'json' 156 | }) 157 | .done(function(data, textStatus, jqXHR){ 158 | //alert(data.tmp_file); 159 | 160 | var html = '
'; 161 | switch (data.status){ 162 | case 'failed': 163 | openModal('okcansel', '認証が必要です', html, 'confirm_del_button('+id+');'); 164 | break; 165 | case 'ok': 166 | location.href = './delete.php?id='+data.id+'&key='+data.key; 167 | break; 168 | } 169 | 170 | }) 171 | .fail(function(jqXHR, textStatus, errorThrown){ 172 | alert(JSON.stringify(jqXHR)); 173 | }) 174 | .always(function( jqXHR, textStatus ) { 175 | }); 176 | } 177 | -------------------------------------------------------------------------------- /asset/js/modal.js: -------------------------------------------------------------------------------- 1 | 2 | function openModal(type, title, body, action){ 3 | switch (type){ 4 | case 'okcansel': 5 | $('#OKCanselModal .modal-title').html(title); 6 | $('#OKCanselModal .modal-body').html(body); 7 | 8 | if(action != null){ 9 | $('#OKCanselModal .f-action').attr('onclick', action); 10 | } 11 | $('#OKCanselModal').modal('show'); 12 | 13 | break; 14 | case 'ok': 15 | $('#OKModal .modal-title').html(title); 16 | $('#OKModal .modal-body').html(body); 17 | 18 | if(action != null){ 19 | $('#OKModal .f-action').attr('onclick', action); 20 | 21 | } 22 | $('#OKModal').modal('show'); 23 | break; 24 | 25 | } 26 | 27 | } 28 | 29 | 30 | function closeModal(){ 31 | $('#OKCanselModal').modal('hide'); 32 | $('#OKModal').modal('hide'); 33 | } 34 | -------------------------------------------------------------------------------- /config/config.php: -------------------------------------------------------------------------------- 1 | 'hoge', 17 | 18 | // 各キーの暗号化用ハッシュ 19 | // ランダムな英数字の羅列を設定してください。 20 | 'key' => 'hogehoge', 21 | 22 | // タイトル 23 | 'title' => 'アップローダー', 24 | 25 | // 保存ファイル数 26 | 'save_max_files' => 500, 27 | 28 | // コメントの最大文字数 29 | 'max_comment' => 80, 30 | 31 | // 1件あたりの最大ファイルサイズ(単位 : MByte) 32 | // php.iniのmemory_limit, post_max_size, upload_max_filesizeの値以下になるようにして下さい。 33 | // nginxを使用している場合はサーバー設定にclient_max_body_sizeをこの値で設定してください。 34 | 'max_file_size' => 2, 35 | 36 | // アップロードできる拡張子 37 | 'extension' => array('zip','rar','lzh'), 38 | 39 | // データベースディレクトリ 40 | 'db_directory' => './db', 41 | 42 | // アップロードしたファイルを置くディレクトリ 43 | 'data_directory' => './data', 44 | 45 | // アップロードされたファイル名を暗号化して管理する (trueまたはfalse デフォルト: false) 46 | // サーバー内ではIDで格納されているファイル名を暗号化された文字列で格納します。 47 | // 暗号に使用するsaltは「key」で指定した値を使用します。 48 | // セキュリティを向上したいときにお使いください。 49 | 'encrypt_filename' => false, 50 | 51 | // バージョン情報です。書き換えないでください。 52 | 'version' => '1.2.1' 53 | ); 54 | } 55 | } -------------------------------------------------------------------------------- /delete.php: -------------------------------------------------------------------------------- 1 | index(); 14 | //配列キーが設定されている配列なら展開 15 | if (!is_null($ret)) { 16 | if(is_array($ret)){ 17 | extract($ret); 18 | } 19 | } 20 | 21 | //データベースの作成・オープン 22 | try{ 23 | $db = new PDO('sqlite:'.$db_directory.'/uploader.db'); 24 | }catch (Exception $e){ 25 | exit; 26 | } 27 | 28 | // デフォルトのフェッチモードを連想配列形式に設定 29 | // (毎回PDO::FETCH_ASSOCを指定する必要が無くなる) 30 | $db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); 31 | 32 | // ファイル名取得 33 | $stmt = $db->prepare("SELECT * FROM uploaded WHERE id = :id"); 34 | $stmt->bindValue(':id', $id); //ID 35 | $stmt->execute(); 36 | $result = $stmt->fetchAll(); 37 | foreach($result as $s){ 38 | $filename = $s['origin_file_name']; 39 | $origin_delkey = $s['del_key']; 40 | } 41 | 42 | // ハッシュを照合して認証が通ればDEL可 43 | if ( PHP_MAJOR_VERSION == '5' and PHP_MINOR_VERSION == '3') { 44 | if( $delkey !== bin2hex(openssl_encrypt($origin_delkey,'aes-256-ecb',$key, true)) ){ 45 | header('location: ./'); 46 | exit; 47 | } 48 | }else{ 49 | if( $delkey !== bin2hex(openssl_encrypt($origin_delkey,'aes-256-ecb',$key, OPENSSL_RAW_DATA)) ){ 50 | header('location: ./'); 51 | exit; 52 | } 53 | } 54 | 55 | // sqlから削除 56 | $sql = $db->prepare("DELETE FROM uploaded WHERE id = :id"); 57 | $sql->bindValue(':id', $id); //ID 58 | if (! $sql->execute()) { 59 | // 削除を実施 60 | } 61 | 62 | //ディレクトリから削除 63 | $ext = substr( $filename, strrpos( $filename, '.') + 1); 64 | if ($encrypt_filename) { 65 | $path = $data_directory.'/' . 'file_' . str_replace(array('\\', '/', ':', '*', '?', '\"', '<', '>', '|'), '',openssl_encrypt($id,'aes-256-ecb',$key)) . '.'.$ext; 66 | if (!file_exists ( $path )) { 67 | $path = $data_directory.'/' . 'file_' . $id . '.'.$ext; 68 | } 69 | } else { 70 | $path = $data_directory.'/' . 'file_' . $id . '.'.$ext; 71 | } 72 | unlink($path); 73 | 74 | 75 | header('location: ./'); 76 | exit(); 77 | -------------------------------------------------------------------------------- /docker-compose.yaml: -------------------------------------------------------------------------------- 1 | version: "3.7" 2 | 3 | services: 4 | web: 5 | build: "./docker" 6 | container_name: "php_apache" 7 | ports: 8 | - "80:80" 9 | volumes: 10 | - ".:/var/www/html/" 11 | -------------------------------------------------------------------------------- /docker/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM php:7.4.8-apache 2 | COPY ./php/php.ini /usr/local/etc/php/ 3 | -------------------------------------------------------------------------------- /docker/php/php.ini: -------------------------------------------------------------------------------- 1 | [Date] 2 | date.timezone = "Asia/Tokyo" 3 | [mbstring] 4 | mbstring.internal_encoding = "UTF-8" 5 | mbstring.language = "Japanese" 6 | -------------------------------------------------------------------------------- /download.php: -------------------------------------------------------------------------------- 1 | index(); 16 | //配列キーが設定されている配列なら展開 17 | if (!is_null($ret)) { 18 | if(is_array($ret)){ 19 | extract($ret); 20 | } 21 | } 22 | 23 | //データベースの作成・オープン 24 | try{ 25 | $db = new PDO("sqlite:".$db_directory."/uploader.db"); 26 | }catch (Exception $e){ 27 | exit; 28 | } 29 | 30 | // デフォルトのフェッチモードを連想配列形式に設定 31 | // (毎回PDO::FETCH_ASSOCを指定する必要が無くなる) 32 | $db->setAttribute(PDO::ATTR_DEFAULT_FETCH_MODE, PDO::FETCH_ASSOC); 33 | 34 | // 選択 (プリペアドステートメント) 35 | $stmt = $db->prepare("SELECT * FROM uploaded WHERE id = :id"); 36 | $stmt->bindValue(':id', $id); //ID 37 | $stmt->execute(); 38 | $result = $stmt->fetchAll(); 39 | foreach($result as $s){ 40 | $filename = $s['origin_file_name']; 41 | $origin_dlkey = $s['dl_key']; 42 | } 43 | 44 | // トークンを照合して認証が通ればDL可 45 | if ( PHP_MAJOR_VERSION == '5' and PHP_MINOR_VERSION == '3') { 46 | if( $dlkey !== bin2hex(openssl_encrypt($origin_dlkey,'aes-256-ecb',$key, true)) ){ 47 | header('location: ./'); 48 | exit; 49 | } 50 | }else{ 51 | if( $dlkey !== bin2hex(openssl_encrypt($origin_dlkey,'aes-256-ecb',$key, OPENSSL_RAW_DATA)) ){ 52 | header('location: ./'); 53 | exit; 54 | } 55 | } 56 | 57 | 58 | // カウンターを増やす 59 | $upd = $db->prepare("UPDATE uploaded SET count = count + 1 WHERE id = :id"); 60 | $upd->bindValue(':id', $id); //ID 61 | $upd->execute(); 62 | 63 | 64 | $ext = substr( $filename, strrpos( $filename, '.') + 1); 65 | if ($encrypt_filename) { 66 | $path = $data_directory.'/' . 'file_' . str_replace(array('\\', '/', ':', '*', '?', '\"', '<', '>', '|'), '',openssl_encrypt($id,'aes-256-ecb',$key)) . '.'.$ext; 67 | if (!file_exists ( $path )) { 68 | $path = $data_directory.'/' . 'file_' . $id . '.'.$ext; 69 | } 70 | } else { 71 | $path = $data_directory.'/' . 'file_' . $id . '.'.$ext; 72 | } 73 | 74 | //var_dump($path); 75 | 76 | header('Content-Type: application/force-download'); 77 | header('Content-Disposition: attachment; filename*=UTF-8\'\''.rawurlencode($filename)); 78 | header('Content-Length: ' . filesize($path)); 79 | ob_end_clean();//ファイル破損を防ぐ //出力バッファのゴミ捨て 80 | readfile($path); 81 | ?> 82 | -------------------------------------------------------------------------------- /index.php: -------------------------------------------------------------------------------- 1 | index(); 18 | //配列キーが設定されている配列なら展開 19 | if (!is_null($ret)) { 20 | if(is_array($ret)){ 21 | extract($ret); 22 | } 23 | } 24 | 25 | //初期設定・DBオープン 26 | include('./app/models/init.php'); 27 | 28 | //modelをインクルード 29 | if (file_exists('./app/models/'.$call.'.php')) { 30 | 31 | include('./app/models/'.$call.'.php'); 32 | //$call名のクラスをインスタンス化 33 | $class = new $call(); 34 | //modelのindexメソッドを呼ぶ仕様 35 | $ret = $class->index(); 36 | //配列キーが設定されている配列なら展開 37 | if (!is_null($ret)) { 38 | if(is_array($ret)){ 39 | extract($ret); 40 | } 41 | } 42 | } 43 | 44 | //viewをインクルード 45 | include('./app/views/header.php'); 46 | if (file_exists('./app/views/'.$call.'.php')) { 47 | include('./app/views/'.$call.'.php'); 48 | } else { 49 | $error = '404 - ページが見つかりません。'; 50 | include('./app/views/error.php'); 51 | } 52 | include('./app/views/footer.php'); 53 | --------------------------------------------------------------------------------