Skip to content

Instantly share code, notes, and snippets.

@Go-Noji
Last active November 21, 2017 03:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save Go-Noji/2b08ba1adb520592fb79ec34b249bd4d to your computer and use it in GitHub Desktop.
Save Go-Noji/2b08ba1adb520592fb79ec34b249bd4d to your computer and use it in GitHub Desktop.
Codeigniterでメインサーバーからファイル用サーバーへファイルをアップロードする(ついでにリネーム・DB操作・サムネ作成) ref: https://qiita.com/Go-Noji/items/8f843b08ddd37f4462b8
//略
$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'
);
//略
<?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');
<?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
));
}
}
<?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>
<?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