檔案上傳是蠻常使用的功能,ci 裡面有內建檔案上傳的功能,但我們當然不想記得繁複的呼叫方式,寫成 helper 來使用是最方便的,今天 news 當作範例示範一下寫法。
news table
CREATE TABLE `news` (
`id` INT NOT NULL AUTO_INCREMENT PRIMARY KEY,
`name` VARCHAR(50) NOT NULL,
`file_name` VARCHAR(100) NOT NULL,
`real_name` VARCHAR(100) NOT NULL
) ENGINE=InnoDB CHARACTER SET utf8 COLLATE utf8_unicode_ci;
application/controllers/News.php
class News extends CI_Controller
{
public function index()
{
$this->load->helper('form');
$this->load->view('news');
}
public function save()
{
$this->load->database();
$this->load->helper('file_manager');
$data = [];
if (has_upload('file')) {
$upload = file_upload('file', 'assets/uploads/news');
if ($upload['status'] == 'fail') {
die($upload['message']);
} else {
$data['file_name'] = $upload['fileName'];
$data['real_name'] = $upload['realName'];
}
}
$data['name'] = uniqid();
$this->db->insert('news', $data);
}
public function download($id)
{
$this->load->database();
$this->load->helper('file_manager');
$row = $this->db->get_where('news', ['id' => $id])->row_array();
force_download("assets/uploads/news/{$row['file_name']}", $row['real_name']);
}
}
index
method 就是簡單的建立一個表單,傳送 name 跟 file 這兩的 field 到 save
儲存,這邊做的都是最簡單的示範,實際情況還是資照需求去修改,但回傳的內容應該都可以應付其他的條件,download
的部份就是調用 file_manager
helper 下載原始的檔案,若非必要,盡量不要在 helper 裡面做 db connection,因為 helper 很有可能會在迴圈裡面出現,這樣 db query 數量會隨資料量增加。
application/views/news.php
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>News</title>
</head>
<body>
<?php echo form_open_multipart('news/save'); ?>
<?php echo form_input('name', uniqid()); ?>
<?php echo form_upload('file'); ?>
<?php echo form_submit('go', 'go'); ?>
<?php echo form_close(); ?>
</body>
</html>
news 的 view,簡單的使用 form
helper 生成。
application/helpers/file_manager_helper.php
if (!function_exists('file_upload')) {
function file_upload($file, $path, array $allows = [])
{
$ci =& get_instance();
$status = 'done';
$message = '';
$fileName = '';
$realName = '';
$config['upload_path'] = $path;
$config['allowed_types'] = (count($allows) > 0) ? implode('|', $allows) : '*';
$config['encrypt_name'] = true;
$ci->load->library('upload', $config);
if (!$ci->upload->do_upload($file)) {
$message = $ci->upload->display_errors();
$status = 'fail';
} else {
$fileData = $ci->upload->data();
$fileName = $fileData['file_name'];
$realName = $fileData['client_name'];
}
return compact('status', 'message', 'fileName', 'realName');
}
}
if (!function_exists('force_download')) {
function force_download($path, $realName)
{
$originFile = urlencode($realName);
$realFile = $path;
header("Pragma: public");
header("Expires: 0");
header("Cache-Control: must-revalidate, post-check=0, pre-check=0");
header("Content-Type: application/force-download");
header("Content-Disposition: attachment; filename=".$originFile);
header("Content-Description: File Transfer");
@readfile($realFile);
}
}
if (!function_exists('has_upload')) {
function has_upload($file)
{
if (isset($_FILES[$file]) && is_uploaded_file($_FILES[$file]['tmp_name'])) {
return true;
}
return false;
}
}
file_upload
function 調用了 upload
的 library,因為主要是傳檔案,所以預設 allows 為全部,當然也有先寫好參數可以傳遞,印象中 codeigniter 的上傳會檢查 mime,所以 allow 的內容可能要符合 mime 的檔名規範,如果要上傳的是圖片的東西,可以用這個 function 去改出一個 image_upload
的 function,再把跟圖片比較有關連的內容放進去,在上傳的時候我們會將檔名使用英文編碼代替,但原始的檔名會一起存到 database,在很多 Linux server 檔案名稱使用非英文的話會無法讀取,所以最好是用純英數去儲存檔案,因為 codeigniter 的 input helper 本身沒有支援 file 的內容,所以寫了一個 has_upload
的 function 來檢查這次的傳輸有沒有上傳檔案。
force_download
這個 function 只要將檔案位置跟原始檔名帶入,便可以下載原始的檔案,即便是中文也沒問題。
沒有留言:
張貼留言