如何使用 Cakephp 3.0 上传文件?
How to upload file using Cakephp 3.0?
我正在尝试在 cakephp 上创建文件上传,但我找不到任何像样的 cakephp 3.0 详细教程,而且我不明白如何安装插件。
我在添加部分有这个
echo $this->Form->create('filename', array('action' => 'upload', 'type' => 'file'));
echo $this->Form->file('filename');
我还没有在控制器中添加任何东西
/**
* Index method
*
* @return void
*/
public function index()
{
$this->paginate = [
'contain' => ['Courses']
];
$this->set('contents', $this->paginate($this->Contents));
$this->set('_serialize', ['contents']);
}
/**
* View method
*
* @param string|null $id Content id.
* @return void
* @throws \Cake\Network\Exception\NotFoundException When record not found.
*/
public function view($id = null)
{
$content = $this->Contents->get($id, [
'contain' => ['Courses']
]);
$this->set('content', $content);
$this->set('_serialize', ['content']);
}
/**
* Add method
*
* @return void Redirects on successful add, renders view otherwise.
*/
public function add()
{
$content = $this->Contents->newEntity();
if ($this->request->is('post')) {
$content = $this->Contents->patchEntity($content, $this->request->data);
if ($this->Contents->save($content)) {
$this->Flash->success('The content has been saved.');
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error('The content could not be saved. Please, try again.');
}
}
$courses = $this->Contents->Courses->find('list', ['limit' => 200]);
$this->set(compact('content', 'courses'));
$this->set('_serialize', ['content']);
}
/**
* Edit method
*
* @param string|null $id Content id.
* @return void Redirects on successful edit, renders view otherwise.
* @throws \Cake\Network\Exception\NotFoundException When record not found.
*/
public function edit($id = null)
{
$content = $this->Contents->get($id, [
'contain' => []
]);
if ($this->request->is(['patch', 'post', 'put'])) {
$content = $this->Contents->patchEntity($content, $this->request->data);
if ($this->Contents->save($content)) {
$this->Flash->success('The content has been saved.');
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error('The content could not be saved. Please, try again.');
}
}
$courses = $this->Contents->Courses->find('list', ['limit' => 200]);
$this->set(compact('content', 'courses'));
$this->set('_serialize', ['content']);
}
/**
* Delete method
*
* @param string|null $id Content id.
* @return void Redirects to index.
* @throws \Cake\Network\Exception\NotFoundException When record not found.
*/
public function delete($id = null)
{
$this->request->allowMethod(['post', 'delete']);
$content = $this->Contents->get($id);
if ($this->Contents->delete($content)) {
$this->Flash->success('The content has been deleted.');
} else {
$this->Flash->error('The content could not be deleted. Please, try again.');
}
return $this->redirect(['action' => 'index']);
}
但在这之后不知道该怎么办。
首先,您需要决定何时处理上传。我设法使用 beforeMarshal 方法和 afterSave 方法创建了一个肮脏的(但有效的)方法(我将在最后解释为什么这两个)。
如果您创建文件输入如下:
<?= $this->Form->file('submittedfile', ['class' => 'form-control input-upload', 'style' => 'height:100px']) ?>
或 hasMany 关联:
<?= $this->Form->file('images.'.$i.'.submittedfile', ['class' => 'form-control input-upload', 'style' => 'height:100px']) ?>
并且您定义了正确的关联:
$this->hasMany('Images', [
'foreignKey' => 'model_id'
]);
您可以在修补和保存实体之前处理这些文件:
public function beforeMarshal(Event $event, \ArrayObject $data, \ArrayObject $options) {
$images = array();
$dir = md5(time().$data['name']);
for ($i = 0; $i < count($data['images']); $i++) {
$image = $data['images'][$i]['submittedfile'];
if (!empty($image['name'])) {
if(!isset($data['id'])) {
$data['temp_dir'] = $dir;
}
else {
$dir = $data['id'];
}
if ($this->Images->uploadFile(array('img', 'model', $dir), $image) === true) {
$images[] = array('name' => pathinfo($image['name'], PATHINFO_FILENAME), 'ext' => pathinfo($image['name'], PATHINFO_EXTENSION));
}
}
}
$data['images'] = $images;
}
这当然是一个例子。我决定检查实体上是否设置了 ID 属性(例如编辑),因为如果没有(例如创建),您必须以某种方式确定正确的路径。
这里有文件上传功能:
public function uploadDir($path = array()) {
return $this->wwwRoot . implode(DS, $path);
}
public function uploadFile($path = array(), $filetoupload = null) {
if (!$filetoupload) {
return false;
}
$dir = new Folder($this->uploadDir($path), true, 755);
$tmp_file = new File($filetoupload['tmp_name']);
if (!$tmp_file->exists()) {
return false;
}
$file = new File($dir->path . DS . $filetoupload['name']);
if (!$tmp_file->copy($dir->pwd() . DS . $filetoupload['name'])) {
return false;
}
$file->close();
$tmp_file->delete();
return true;
}
如果您在没有主实体 ID 的子目录时添加图像,则必须在获得 ID 后立即重命名目录:
public function afterSave(Event $event, Entity $entity, \ArrayObject $options) {
if(!empty($entity->temp_dir)) {
$this->Images->renameFolder(array('img', 'model', $entity->temp_dir),$entity->id);
}
}
呼叫:
public function renameFolder($path = array(), $newName) {
$oldPath = $this->wwwRoot . implode(DS, $path);
$nameToChange = array_pop($path);
array_push($path, $newName);
$newPath = $this->wwwRoot . implode(DS, $path);
return rename($oldPath, $newPath);
}
- 使用 beforeMarshal,您可以在整个实体准备好保存之前将文件数据注入实体结构(使用关联)。
- 使用 afterSave,您可以识别主要对象 ID 并调用您之前上传的对象集。
- 请记住设置将文件保存到目录的递归权限,以及创建和重命名目录的权限。
我正在尝试在 cakephp 上创建文件上传,但我找不到任何像样的 cakephp 3.0 详细教程,而且我不明白如何安装插件。
我在添加部分有这个
echo $this->Form->create('filename', array('action' => 'upload', 'type' => 'file'));
echo $this->Form->file('filename');
我还没有在控制器中添加任何东西
/**
* Index method
*
* @return void
*/
public function index()
{
$this->paginate = [
'contain' => ['Courses']
];
$this->set('contents', $this->paginate($this->Contents));
$this->set('_serialize', ['contents']);
}
/**
* View method
*
* @param string|null $id Content id.
* @return void
* @throws \Cake\Network\Exception\NotFoundException When record not found.
*/
public function view($id = null)
{
$content = $this->Contents->get($id, [
'contain' => ['Courses']
]);
$this->set('content', $content);
$this->set('_serialize', ['content']);
}
/**
* Add method
*
* @return void Redirects on successful add, renders view otherwise.
*/
public function add()
{
$content = $this->Contents->newEntity();
if ($this->request->is('post')) {
$content = $this->Contents->patchEntity($content, $this->request->data);
if ($this->Contents->save($content)) {
$this->Flash->success('The content has been saved.');
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error('The content could not be saved. Please, try again.');
}
}
$courses = $this->Contents->Courses->find('list', ['limit' => 200]);
$this->set(compact('content', 'courses'));
$this->set('_serialize', ['content']);
}
/**
* Edit method
*
* @param string|null $id Content id.
* @return void Redirects on successful edit, renders view otherwise.
* @throws \Cake\Network\Exception\NotFoundException When record not found.
*/
public function edit($id = null)
{
$content = $this->Contents->get($id, [
'contain' => []
]);
if ($this->request->is(['patch', 'post', 'put'])) {
$content = $this->Contents->patchEntity($content, $this->request->data);
if ($this->Contents->save($content)) {
$this->Flash->success('The content has been saved.');
return $this->redirect(['action' => 'index']);
} else {
$this->Flash->error('The content could not be saved. Please, try again.');
}
}
$courses = $this->Contents->Courses->find('list', ['limit' => 200]);
$this->set(compact('content', 'courses'));
$this->set('_serialize', ['content']);
}
/**
* Delete method
*
* @param string|null $id Content id.
* @return void Redirects to index.
* @throws \Cake\Network\Exception\NotFoundException When record not found.
*/
public function delete($id = null)
{
$this->request->allowMethod(['post', 'delete']);
$content = $this->Contents->get($id);
if ($this->Contents->delete($content)) {
$this->Flash->success('The content has been deleted.');
} else {
$this->Flash->error('The content could not be deleted. Please, try again.');
}
return $this->redirect(['action' => 'index']);
}
但在这之后不知道该怎么办。
首先,您需要决定何时处理上传。我设法使用 beforeMarshal 方法和 afterSave 方法创建了一个肮脏的(但有效的)方法(我将在最后解释为什么这两个)。
如果您创建文件输入如下:
<?= $this->Form->file('submittedfile', ['class' => 'form-control input-upload', 'style' => 'height:100px']) ?>
或 hasMany 关联:
<?= $this->Form->file('images.'.$i.'.submittedfile', ['class' => 'form-control input-upload', 'style' => 'height:100px']) ?>
并且您定义了正确的关联:
$this->hasMany('Images', [
'foreignKey' => 'model_id'
]);
您可以在修补和保存实体之前处理这些文件:
public function beforeMarshal(Event $event, \ArrayObject $data, \ArrayObject $options) {
$images = array();
$dir = md5(time().$data['name']);
for ($i = 0; $i < count($data['images']); $i++) {
$image = $data['images'][$i]['submittedfile'];
if (!empty($image['name'])) {
if(!isset($data['id'])) {
$data['temp_dir'] = $dir;
}
else {
$dir = $data['id'];
}
if ($this->Images->uploadFile(array('img', 'model', $dir), $image) === true) {
$images[] = array('name' => pathinfo($image['name'], PATHINFO_FILENAME), 'ext' => pathinfo($image['name'], PATHINFO_EXTENSION));
}
}
}
$data['images'] = $images;
}
这当然是一个例子。我决定检查实体上是否设置了 ID 属性(例如编辑),因为如果没有(例如创建),您必须以某种方式确定正确的路径。
这里有文件上传功能:
public function uploadDir($path = array()) {
return $this->wwwRoot . implode(DS, $path);
}
public function uploadFile($path = array(), $filetoupload = null) {
if (!$filetoupload) {
return false;
}
$dir = new Folder($this->uploadDir($path), true, 755);
$tmp_file = new File($filetoupload['tmp_name']);
if (!$tmp_file->exists()) {
return false;
}
$file = new File($dir->path . DS . $filetoupload['name']);
if (!$tmp_file->copy($dir->pwd() . DS . $filetoupload['name'])) {
return false;
}
$file->close();
$tmp_file->delete();
return true;
}
如果您在没有主实体 ID 的子目录时添加图像,则必须在获得 ID 后立即重命名目录:
public function afterSave(Event $event, Entity $entity, \ArrayObject $options) {
if(!empty($entity->temp_dir)) {
$this->Images->renameFolder(array('img', 'model', $entity->temp_dir),$entity->id);
}
}
呼叫:
public function renameFolder($path = array(), $newName) {
$oldPath = $this->wwwRoot . implode(DS, $path);
$nameToChange = array_pop($path);
array_push($path, $newName);
$newPath = $this->wwwRoot . implode(DS, $path);
return rename($oldPath, $newPath);
}
- 使用 beforeMarshal,您可以在整个实体准备好保存之前将文件数据注入实体结构(使用关联)。
- 使用 afterSave,您可以识别主要对象 ID 并调用您之前上传的对象集。
- 请记住设置将文件保存到目录的递归权限,以及创建和重命名目录的权限。