Last active
November 21, 2017 03:00
-
-
Save Go-Noji/2b08ba1adb520592fb79ec34b249bd4d to your computer and use it in GitHub Desktop.
Codeigniterでメインサーバーからファイル用サーバーへファイルをアップロードする(ついでにリネーム・DB操作・サムネ作成) ref: https://qiita.com/Go-Noji/items/8f843b08ddd37f4462b8
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
//略 | |
$config['csrf_protection'] = TRUE; | |
$config['csrf_token_name'] = 'csrf_test_name'; | |
$config['csrf_cookie_name'] = 'csrf_cookie_name'; | |
$config['csrf_expire'] = 7200; | |
$config['csrf_regenerate'] = FALSE; | |
$config['csrf_exclude_uris'] = array( | |
'media/external_upload' | |
); | |
//略 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
//画像サーバーのドメイン(''にすればファイルサーバー無しと判断する)、末尾の/は付けないこと | |
//デフォルトのCodeigniterで扱うURLにくっついている'index.php'を外す処理をしているなら末尾の'/index.php'は削除 | |
$config['img_server'] = 'https://○○○.com/index.php'; | |
//ホワイトリストIP番号 | |
//この配列の中に存在しないIPアドレスからのアップロードを受け付けない | |
$config['ip_white_list'] = array('111.111.11.11'); | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Class Media | |
* @property CI_Loader $load | |
* @property CI_Input $input | |
* @property CI_Upload $upload | |
* @property Media_model $media_model | |
*/ | |
class Media extends CI_Controller { | |
/** | |
* 必要なモノをロード | |
* @return void | |
*/ | |
public function __construct() | |
{ | |
parent::__construct(); | |
//モデルのロード | |
$this->load->model('media_model'); | |
//ヘルパーをロード | |
$this->load->helper(array('url', 'form')); | |
//画像サーバー設定読込 | |
$this->config->load('img_server'); | |
//アップロードライブラリの読み込み&設定 | |
$config = array( | |
// ファイルのアップロード制限 | |
"allowed_types"=>"jpg|jpeg|gif|png", | |
//ファイル名が被ったときは上書きする | |
'overwrite' => TRUE, | |
// ファイルのアップロード先を決める | |
"upload_path"=>APPPATH.'../uploads' | |
); | |
$this->load->library('upload', $config); | |
} | |
/** | |
* 設定されているホワイトリストIP以外のアクセスを弾くメソッド | |
* @return void | |
*/ | |
private function _ip_filter() | |
{ | |
foreach ($this->config->item('ip_white_list') as $ip) | |
{ | |
if(isset($_SERVER['REMOTE_ADDR']) && $ip === $_SERVER['REMOTE_ADDR']) { | |
return; | |
} | |
} | |
die('IPがやべーぞ'); | |
} | |
/** | |
* ファイルをCI_Uploadクラスでアップロードする | |
* $upload->dataの返り値を返す | |
* @return array | |
*/ | |
private function _up() | |
{ | |
try | |
{ | |
if (!isset($_FILES['asset']['error']) || !is_int($_FILES['asset']['error'])) { | |
throw new Exception('パラメータが不正です'); | |
} | |
if($this->upload->do_upload('asset')) | |
{ | |
return $this->upload->data(); | |
} | |
//ファイルのアップロードに失敗した場合 | |
throw new Exception($this->upload->display_errors('<p>', '</p>')); | |
} | |
catch (Exception $e) | |
{ | |
die($e->getMessage()); | |
} | |
} | |
/** | |
* フォームから値を受け取る | |
* _up()を呼び出したらモデルへ | |
* @return void | |
*/ | |
public function upload() | |
{ | |
//モデルへ情報を投げる | |
print $this->media_model->upload($this->_up()); | |
} | |
/** | |
* 外部からデータを受け取る | |
* 指定されたIPアドレス以外は弾く | |
*/ | |
public function external_upload() | |
{ | |
//外部からのアクセス専用なので、許可なきIPは滅 | |
$this->_ip_filter(); | |
//モデルへ情報を投げる | |
print $this->media_model->external_upload($this->_up()); | |
} | |
/** | |
* 画面の表示 | |
* @return void | |
*/ | |
public function index() | |
{ | |
//画像パスの設定を読み込む | |
$path = base_url().'media'; | |
if($this->config->item('img_server')) | |
{ | |
$path = $this->config->item('img_server').'/media'; | |
} | |
//CSRF TOKENの名前 | |
$token_name = $this->security->get_csrf_token_name(); | |
$this->load->view('media', array( | |
'path' => $path, | |
'token_name' => $token_name | |
)); | |
} | |
} | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
defined('BASEPATH') OR exit('No direct script access allowed'); | |
?><!DOCTYPE html> | |
<html lang="ja"> | |
<head> | |
<meta charset="utf-8"> | |
<meta name="viewport" content="width=device-width"> | |
<title>アップロードDEMO</title> | |
</head> | |
<body data-url="<?php echo $path; ?>"> | |
<div class="wrap"> | |
<div class="dropArea"> | |
<?php echo form_open_multipart('/media/upload/'); ?> | |
<h4 class="managementFormBoxTitle">ファイルをアップロードする</h4> | |
<div class="fileDropArea"> | |
<p class="fileDropComment">ファイルをドロップ<br/> | |
または<br/> | |
<label class="fileChooseBtn"> | |
ファイルを選択 | |
<?php echo form_upload(array( | |
'name' => 'asset', | |
'class' => 'file', | |
'value' => 'ファイルを選択' | |
)); ?> | |
</label> | |
<span id="numbers" style="display: none;"><span id="numberNow"></span>/<span id="numberCount"></span> 件処理中...</span> | |
</p> | |
</div> | |
<p id="alerts"></p> | |
<?php echo form_close(); ?> | |
</div> | |
<div class="managementTableSpace picArea"> | |
<ul class="mediaDisplayTypeTileListBox picBox" style="position: relative;"></ul> | |
</div> | |
</div> | |
<script> | |
(function(){ | |
//トークン取得 | |
var token = document.querySelector('[name = <?php echo $token_name; ?>]').value; | |
//パス取得 | |
var path = window.location.href; | |
//進行状況部分 | |
var numbers = document.getElementById('numbers'); | |
//処理中のファイル番号部分 | |
var numberNow = document.getElementById('numberNow'); | |
//処理中のファイル全体数部分 | |
var numberCount = document.getElementById('numberCount'); | |
//警告部分 | |
var alerts = document.getElementById('alerts'); | |
//画像投稿 | |
function upload(targets){ | |
numbers.style.display = 'block'; | |
//投稿された画像らしきファイルの数 | |
var length = targets.length; | |
numberCount.innerHTML = length; | |
//カウント変数 | |
var i = 0; | |
//サーバーエラー確認 | |
var handleErrors = function(response) { | |
if (!response.ok) { | |
throw Error(response.statusText); | |
} | |
return response; | |
} | |
//まだアップロードファイルがあるか確認する | |
var loop = function (response) { | |
console.log(response); | |
i++; | |
if(i < length){ | |
upload(); | |
} | |
else{ | |
numbers.style.display = 'none'; | |
} | |
} | |
//サーバーエラー発生時処理 | |
var reject = function() { | |
alerts.innerHTML = alerts.innerHTML + '<span>'+(i + 1)+'番目:'+targets[i].name + 'のアップロードに失敗しました</span><br />'; | |
} | |
//アップロード処理 | |
var up = function(){ | |
if(targets[i].type.indexOf('image/') === 0){ | |
//進捗表示 | |
numberNow.innerHTML = i; | |
//ファイル | |
var fd = new FormData(); | |
fd.append('asset', targets[i]); | |
fd.append('<?php echo $token_name; ?>', token); | |
//アップする | |
fetch(path + '/upload', { | |
method: 'POST', | |
body: fd, | |
mode: 'cors', | |
credentials: 'include' | |
}) | |
.then(handleErrors) | |
.then(loop) | |
.catch(reject); | |
return; | |
} | |
//画像でないファイルをアップロード | |
alerts.innerHTML = alerts.innerHTML + '<span>'+(i + 1)+'番目:'+targets[i].name + 'は画像ではありません</span><br />'; | |
} | |
//アップロード開始 | |
up(); | |
} | |
//画像投稿 | |
var fileBtn = document.getElementsByClassName('file')[0]; | |
fileBtn.addEventListener('change', function (e) { | |
upload(e.target.files); | |
}); | |
//画像ドロップ | |
var dropArea = document.getElementsByClassName('dropArea')[0]; | |
//ドラッグ途中 | |
dropArea.addEventListener('dragover', function (e) { | |
e.preventDefault(); | |
e.dataTransfer.dropEffect = 'copy'; | |
}); | |
//ドロップ | |
dropArea.addEventListener('drop', function (e) { | |
e.preventDefault(); | |
upload(e.dataTransfer.files); | |
}); | |
})(); | |
</script> | |
</body> | |
</html> | |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/** | |
* Class Media_model | |
* @property CI_DB $db | |
* @property CI_Image_lib $image_lib | |
*/ | |
class Media_model extends CI_Model { | |
/** | |
* コンストラクタ | |
* 必要なクラスのロード | |
* @return void | |
*/ | |
public function __construct() | |
{ | |
parent::__construct(); | |
$this->load->database(); | |
} | |
/** | |
* DBにデータをinsertする | |
* 上書きが発生したかを判断し、発生したらTRUE、発生しなかったらFALSEを返す | |
* @param string $new_name | |
* @param string $original_name | |
* @return bool | |
*/ | |
private function _input_db($new_name, $original_name) | |
{ | |
//data_mediaというテーブルにデータを突っ込みたいとする | |
//さらに、同名のデータが既にあったら何もせずTRUEを返したいとする | |
//テーブル名 | |
$table = 'data_media'; | |
//既存の被りデータ探し | |
$this->db->where('new_name', $new_name); | |
$query = $this->db->get($table); | |
//被りがあるかどうかの判定 | |
$data = $query->result(); | |
if(isset($data[0])) | |
{ | |
//被りがあったので上書きフラグTRUE | |
return TRUE; | |
} | |
//被りが無かったのでDBにinsert | |
$this->db->insert($table, array( | |
'original_name' => $original_name, | |
'new_name' => $new_name | |
)); | |
//上書きフラグはFALSE | |
return FALSE; | |
} | |
/** | |
* リネーム処理 | |
* @param array $data | |
* @return string | |
*/ | |
private function _rename($data) | |
{ | |
//例えば、先頭の0を消す処理 | |
try | |
{ | |
$new_name = ltrim($data['file_name'], '0'); | |
if(rename($data['full_path'], $data['file_path'].$new_name)) | |
{ | |
return $new_name; | |
} | |
throw new Exception('ファイルのリネームに失敗しました'); | |
} | |
catch (Exception $exception) | |
{ | |
die($exception->getMessage()); | |
} | |
} | |
/** | |
* サムネイルを生成する | |
* @param string $file_path | |
* @param string $new_name | |
* @return void | |
*/ | |
private function _create_thumb($file_path, $new_name) | |
{ | |
//パスを変数に格納 | |
$path = $file_path.$new_name; | |
//画像ファイルでなかったら処理を中断 | |
$extension = strtolower(pathinfo(realpath($path), PATHINFO_EXTENSION)); | |
if ( | |
$extension !== 'jpeg' && | |
$extension !== 'jpg' && | |
$extension !== 'gif' && | |
$extension !== 'png' | |
) | |
{ | |
return; | |
} | |
//作成するサムネイルの種類を設定 | |
$thumbConfigs = array( | |
array( | |
'suffix' => '_big', | |
'width' => 1000 | |
), | |
array( | |
'suffix' => '_middle', | |
'width' => 400 | |
), | |
array( | |
'suffix' => '_small', | |
'width' => 130 | |
) | |
); | |
foreach ($thumbConfigs as $thumbConfig) | |
{ | |
//イメージライブラリの設定 | |
$config = array( | |
'source_image' => $path, | |
'create_thumb' => TRUE, | |
'thumb_marker' => $thumbConfig['suffix'], | |
'width' => $thumbConfig['width'] | |
); | |
$this->image_lib->initialize($config); | |
//サムネイル生成 | |
try | |
{ | |
if( ! $this->image_lib->resize()) | |
{ | |
throw new Exception($this->image_lib->display_errors()); | |
} | |
} | |
catch (Exception $exception) | |
{ | |
die($exception->getMessage()); | |
} | |
} | |
} | |
/** | |
* 外部ファイルサーバー指定があった場合は現地のコントローラを叩く | |
* @param array $data | |
* @return string | |
*/ | |
public function upload($data) | |
{ | |
//以下三行はブラウザに接続を切らせないための処理 | |
//長時間(30秒とか)のアップロード時のみ必要なので、極端な場合を除きいらないかも | |
echo ''; | |
@ob_flush(); | |
flush(); | |
//元のファイル名 | |
$original_name = $data['client_name']; | |
//リネーム処理が必要ならこのタイミングで | |
$new_name = $this->_rename($data); | |
//既に存在しているファイル名ならば上書きフラグをonに、そうでなければDBに登録 | |
$override = $this->_input_db($new_name, $original_name); | |
//外部画像サーバーが設定されているかどうか | |
if($this->config->item('img_server')) | |
{ | |
//外部画像サーバーが設定されていたらそこのMediaコントローラーに狙いを定める | |
$url = $this->config->item('img_server').'/media/external_upload'; | |
//ファイルをhttpで送れるよう加工 | |
$file = file_get_contents($data['file_path'].$new_name); | |
//ファイルタイプを取得 | |
$finfo = finfo_open(FILEINFO_MIME_TYPE); | |
$type = finfo_file($finfo, $data['file_path'].$new_name); | |
finfo_close($finfo); | |
//改行文字の設定 | |
$rn = "\r\n"; | |
//画像サーバーに投げるヘッダーを作成 | |
$boundary = '--------------------------'.microtime(TRUE); | |
$headers = 'Accept-language: ja'.$rn. | |
'Content-Type: multipart/form-data; boundary='.$boundary.$rn; | |
//画像サーバーに投げるcontent部分の作成 | |
$content = '--'.$boundary.$rn. | |
'Content-Disposition: form-data; name="asset"; filename="'.$new_name. '"' .$rn. | |
'Content-Type: '.$type.$rn.$rn. | |
$file .$rn. | |
'--'.$boundary.'--'.$rn; | |
//投げる内容をまとめる | |
$opts['http'] = [ | |
'method' => 'POST', | |
'header' => $headers, | |
'content' => $content | |
]; | |
$context = stream_context_create($opts); | |
//お待たせしました、投げます | |
file_get_contents($url, FALSE, $context); | |
//このサーバーの画像ファイル削除 | |
unlink($data['file_path'].$new_name); | |
} | |
else | |
{ | |
//外部サーバーが設定されていなかったのでサムネイル作成 | |
$this->_create_thumb($data['file_path'], $new_name); | |
} | |
//上書き情報をControllerに返す | |
return $override; | |
} | |
/** | |
* 外部からのファイルアップロードに対応する | |
* リネームとサムネイル作成 | |
* @param array $data | |
* @return void | |
*/ | |
public function external_upload($data) | |
{ | |
//リネーム処理が必要ならこのタイミングで | |
$new_name = $this->_rename($data); | |
//サムネイル作成 | |
$this->_create_thumb($data['file_path'], $new_name); | |
} | |
} | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment