php多文件上传
多文件上传时,文件是二维数组,需要将二位数组遍历成一维数组,并且一维的键跟二维数组的值相结合,
上一个代码部分:
// var_dump($fileInfo);
foreach ($fileInfo as $k => $v) {
// var_dump($k, $v);本来是个二位数组,将二位数组的键和值单独拿出来,他的值,是二维数组的一维数组,所以需要再次遍历$v
// k就是原来的每个键 V就是每个键的值
// var_dump($v); //打印出来你发现,$v又是一个一维数组,再次遍历这个一维数组
foreach ($v as $kk => $vv) {
// var_dump($kk, $vv);
if ($kk == $kk) {
// var_dump($kk);
// 相当于数组就是0=>name=>值
// kk是第一个数组的0 也是等于第二个数组的0 验证吧,懵逼了
$files[$kk][$k] = $vv;
// var_dump($files);
}
}
return $files;
}
封装函数的控制器部分:
代码部分:
<?php
//公共函数库 将多文件散列的信息整合
// 将二维数组转为一维数组时的封装函数
function formData($fileInfo)
{
// var_dump($fileInfo);
foreach ($fileInfo as $k => $v) {
// var_dump($k, $v);本来是个二位数组,将二位数组的键和值单独拿出来,他的值,是二维数组的一维数组,所以需要再次遍历$v
// k就是原来的每个键 V就是每个键的值
// var_dump($v); //打印出来你发现,$v又是一个一维数组,再次遍历这个一维数组
foreach ($v as $kk => $vv) {
// var_dump($kk, $vv);
if ($kk == $kk) {
// var_dump($kk);
// 相当于数组就是0=>name=>值
// kk是第一个数组的0 也是等于第二个数组的0 验证吧,懵逼了
$files[$kk][$k] = $vv;
// var_dump($files);
}
}
return $files;
}
}
///////////////////上面是多文件上传操作//////////////////
// 将返回的错误等信息封装到upload()函数中
function upload($fileInfo, $exts = ['jpg', 'png', 'gif', 'jpeg', 'wbmp'], $maxSize = 2097152, $uploadPath = 'storage')
{
if ($fileInfo['error'] == 0) {
//分割文件名
$arr = explode('.', $fileInfo['name']);
//拿到文件名的尾部
$ext = end($arr);
//拿到文件名的头部
$prefix = array_shift($arr);
//判断文件后缀是否合法
if (!in_array($ext, $exts)) {
$res['error'] = '非法的文件类型';
};
//检查路径是否存在
if (!file_exists($uploadPath)) {
mkdir($uploadPath, 0777, true);
}
//将文件名格式化
$des = $uploadPath . '/' . date('YmdHms', time()) . md5($prefix) . time() . '.' . $ext;
$result = move_uploaded_file($fileInfo['tmp_name'], $des);
if (!$result) {
$res['error'] = '文件移动失败';
} else {
$res['fileRealPath'] = $des;
$res['info'] = $fileInfo['name'] . '上传成功';
}
return $res;
} else {
// var_dump($fileInfo['error']);
switch ($fileInfo['error']):
case 1:
$res['error'] = '<p style="color:red">文件超过`php.ini`中`upload_max_filesize`值</p>';
break;
case 2:
$res['error'] = '<p style="color:red">文件大小超过表单中`MAX_FILE_SIZE`指定的值</p>';
break;
case 3:
$res['error'] = '<p style="color:red">文件只有部分被上传</p>';
break;
case 4:
$res['error'] = '<p style="color:red">没有文件被上传</p>';
break;
case 5:
$res['error'] = '<p style="color:red">找不到临时文件夹</p>';
break;
case 6:
$res['error'] = '<p style="color:red">文件写入失败</p>';
break;
default:
$res['error'] = '<p style="color:red">系统错误</p>';
break;
endswitch;
return $res;
}
}
封装函数的视图层部分并且控制器部分的调用:
通过封装的函数接收到数据并进行对数据的渲染
<?php
//获取文件信息$__file
require 'common.php';
// 接收前端的数据
// var_dump($_FILES);超全局函数拿到数据 数据都存在于avater里面
$fileInfo = $_FILES['avatar'];
// var_dump($fileInfo);
// var_dump(upload($fileInfo));
// $res = formData($fileInfo);
$res = upload($fileInfo);
var_dump($res);
// $res = $fileInfo;
// var_dump($_FILES);
// var_dump($res);
if (count($res) == 2) {
//使用count()判断数组中返回的元素数目,如果返回2,代表成功
echo "<p>{$res['info']}</p>";
echo "<p><img style='border-radius:50%;width:100px';height:50% src='{$res['fileRealPath']}'></p>";
// 插入数据表
// 存json数据片段
$avatar = json_encode($res['fileRealPath']);
// var_dump($avatar);
$uid = $_GET['uid'] ?? 1;
$pdo = new pdo('mysql:host=localhost;charset=utf8;dbname=phpcn', 'root', '123456', [PDO::ATTR_DEFAULT_FETCH_MODE => PDO::FETCH_ASSOC, PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING]);
// 存数据
// $sql = 'UPDATE `mj_user` SET `avatar`= ? WHERE `uid`=?';
// 取数据
$sql = 'SELECT `avatar` FROM `mj_user` WHERE `uid`=?';
// 预处理一家sql数据
$stmt = $pdo->prepare($sql);
//绑定要执行的的语句,并执行,数组的方式
// $stmt->execute([$avatar, $uid]);
// 下面是取数据
$stmt->execute([$uid]);
$avatarUrl = json_decode($stmt->fetch()['avatar']); //取出的是图片路径片段 有的时候需要拼接完整路径
echo '<br>';
var_dump($avatarUrl);
echo "<img style='border-radius:50%;width:100px';height:50% src='{$avatarUrl}'>";
echo '<br>';
// 下面是判断收影响的行数
if ($stmt->rowCount() == 1) {
echo json_encode(['status' => 1, 'msg' => '头像修改成功'], 320);
}
} else {
echo "<p style='color:red'>{$res['error']}</p>";
}
单文件及多文件的上传操作**
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>文件上传</title>
</head>
<body>
<!-- 当上传文件时 enctype值需要设置为multipart/form-data,文件时二进制 -->
<form action="doUpload.php" method="post" enctype="multipart/form-data">
<label for="avatar">头像</label>
<input type="file" name="avatar" id="avatar">
<button>文件上传提交</button>
</form>
<!-- 多文件上传 -->
<!-- 当上传文件时 enctype值需要设置为multipart/form-data,文件时二进制 -->
<!-- <form action="doUpload.php" method="post" enctype="multipart/form-data">
<label for="avatar">头像</label> -->
<!-- 多文件上传需要将name属性数组化,因为上传的多个文件是一个数组的格式,并且需要给input增加一个multiple属性 表明为多文件上传 -->
<!-- <input type="file" name="avatar[]" id="avatar" multiple>
<button>文件上传提交</button>
</form> -->
</body>
</html>
MVC架构模式运行原理及容器的注入
1.0版本
MVC架构 就是将视图层跟模型层数据分离,注入到控制器层,控制器层处理视图层跟模型层的数据,
下面的代码 没有贴composer.json,自己找个弄进去,空间命名chloe\app;即可,复制即运行,最后的数据库文件,放到php学习完了之后贴进去,想要下载的,等晚点吧
v层代码:
<?php
namespace chloe\app;
//使用控制层的时候将这里的model.php注释掉
//require 'Model.php';
class View
{
public function fetch($data)
{
// .= shi 组合相加
$table = '<table border="1" cellspacing="0" cellpadding="5" align="center">';
$table .= '<caption>课程信息表</caption>';
$table .= '
<tr align="center">
<td>编号</td>
<td>名称</td>
<td>封面</td>
<td>课程简介</td>
<td>创建时间</td>
<td>操作</td>
</tr>
';
foreach ($data as $list) {
// foreach遍历data的数据
$table .= '<tr>';
$table .= '<td>' . $list['cou_id'] . '</td>';
$table .= '<td>' . $list['title'] . '</td>';
$table .= "<td><img style='width:100px' src='{$list['pic']}' alt='课程封面' ></td>";
$table .= '<td>' . $list['info'] . '</td>';
$table .= '<td>' . date("Y-m-d H:m:s", $list['add_time']) . '</td>';
$table .= '<td><button>删除</button> <button>编辑</button> </td>';
$table .= '</tr>';
}
$table .= '</table>';
return $table;
}
}
//控制器中操作,这里注释掉
//$data = (new Model)->getData();
//echo (new View)->fetch($data);
m层代码:
<?php
namespace chloe\app;
use pdo;
class Model
{
public function getData()
{
return (new PDO('mysql:host=localhost;charset=utf8;dbname=phpcn', 'root', '123456', [PDO::ATTR_ERRMODE => PDO::ERRMODE_WARNING]))->query('SELECT `cou_id`,`title`,`pic`,`info`,`add_time`FROM `mj_course_lists` ORDER BY `cou_id` DESC LIMIT 6')->fetchAll();
}
public function editData()
{
}
}
// 模型文件
// 获取模型数据
// var_dump((new Model)->getData());
控制器部分代码:
<?php
namespace chloe\app;
require __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
class Controller
{
//中间层 控制器层
//将外部依赖的对象 model跟view 在具体的方法中注入进来
function index(Model $model, View $view)
{
//获取数据
$data = $model->getData();
//渲染数据
return $view->fetch($data);
}
function edit(Model $model, View $view)
{
$model->editData();
}
}
//这里的new model 跟new view不就是在原来的模型层跟视图层new的吗 然后将new赋值给$model 然后传入controller里面,能看懂么,看不懂啪啪啪打脸
$model = new Model;
$view = new View;
//然后注入到控制器里面
echo (new Controller)->index($model, $view);
// (new Controller)->index($model, $view);
2.0版本将注入点不放到某个方法中,就是不注入到具体那个方法中,将注入点注入到构造器中,放到作用域中
代码部分:
<?php
namespace chloe\app;
require __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
class Controller1
{
protected $model;
protected $view;
//进一步格式化 将外部注入依赖的对象 model view 在构造器中注入进来,完成外部对象在多个方法中共享
function __construct($model, $view)
{
$this->model = $model;
$this->view = $view;
}
//中间层 控制器层
//将外部依赖的对象 model跟view 在具体的方法中注入进来
function index()
{
//获取数据
$data = $this->model->getData();
//渲染数据
return $this->view->fetch($data);
}
function edit()
{
$this->model->editData();
}
}
//这里的new model 跟new view不就是在原来的模型层跟视图层new的吗 然后将new赋值给$model 然后传入controller里面,能看懂么,看不懂啪啪啪打脸
$model = new Model;
$view = new View;
$c = new Controller1($model, $view);
echo $c->index();
// (new Controller)->index($model, $view);
截图示例:
截图中的echo不能直接访问,需要访问new里面的方法,index()具体方法,截图是php走的一个流程
3.0版本,将依赖对象注入放到容器中
容器中使用回调函数回调绑定的参数别名及方法,在容器中将方法赋值给容器中的对象,方法=容器中的某个成员。
代码部分:
<?php
/***
* 如果当前类锁依赖的外部对象过多,名称很长,将依赖的所有外部对象放到一个容器中进行统一管理。并且可以起名
*
*
*
*/
namespace chloe\app;
use Closure;
//将容器里面的对象放到一个数组中,用于存放外部依赖的多个对象,把容器当做一个数组,数组的下键就是别名,值就是外部对象,依赖的对象
//服务容器 一个产生对象的工厂 自动生产类,对象的工厂
class Container
{
//对象容器
protected $instances = [];
/**
* 绑定一个类标识、闭包、实例到容器
* @access public
* @param string|array $abstract 类标识或者接口的别名 alias
* @param mixed $concrete 要绑定的类、闭包或者实例
*
*/
//往容器数组中绑定对象 $concrete是绑定的闭包 Closure闭包
public function bind($abstract, Closure $concrete) //第一个参数是别名 第二个参数,是具体绑定的对象
{
// 将值赋值给数组, $abstract是数组的键, $concrete是数组的值
$this->instances[$abstract] = $concrete;
}
//下面是取值
public function make($abstract, $params = [])
{
// 刚刚在上面绑定了一个闭包函数方法,已经将闭包函数方法赋值给了 $instances
// 第二个是传入的参数
return call_user_func_array($this->instances[$abstract], $params);
}
}
控制器:
而控制器中将容器实例化,实例化后在给容器中的数组传值,传值后实例化控制器,使用容器中的方法将model模型跟view模型注入到容器中,在控制器中的构造函数中调用容器中的回调函数返回数组的下键跟值,再在某个方法中使用
代码部分:
<?php
namespace chloe\app;
require __DIR__ . DIRECTORY_SEPARATOR . '..' . DIRECTORY_SEPARATOR . 'vendor' . DIRECTORY_SEPARATOR . 'autoload.php';
class Controller2
{
protected $container;
//进一步格式化 将外部注入依赖的对象 model view 在构造器中注入进来,完成外部对象在多个方法中共享
function __construct($container)
{
// 构造器 外部已经声明了一个container 将传入的值赋值给本作用域中的container
$this->container = $container;
}
//中间层 控制器层
//将外部依赖的对象 model跟view 在具体的方法中注入进来
function index()
{
//获取数据
// 传入值后调用容器中的make方法 也就是将实例化的new Model当做一个别名model
$data = $this->container->make('model')->getData();
//渲染数据
return $this->container->make('view')->fetch($data);
}
function edit()
{
$this->container->make('model')->editData();
}
}
// 因为container在一个命名空间中,所以实例化的时候并不需要引入
// 将container实例化 实例化的是容器中的类
$container = new Container;
// bind()方法中传入一个model值是实例化的 new model
// 上面先实例化,实例化后再下面绑定到bind方法的数组中
$container->bind('model', function () {
return new Model;
});
$container->bind('view', function () {
return new View;
});
// 将容器传入controller2类的构造器中
$c2 = new Controller2($container);
// 上面将容器实例化后绑定的键 闭包传入到container中,因为在容器中instances是一个数组,
// 所以这里传入的也是一个数组
echo $c2->index();
我自己也稀里糊涂的,上截图吧