Laravel 5.1对文件进行存储、移动和删除操作操作实例
Laravel 基于 Flysystem 提供了强大的文件系统对文件进行存储和删除,该文件系统和缓存一样,支持多种驱动,这些驱动包括本地驱动、FTP、Amazon S3以及 Rackspace,在这些驱动之上提供了统一的API方便随时切换驱动而不需要修改任何业务逻辑代码。
既然API方法一致,那么这里作为示例,我们使用本地驱动来演示如何使用文件系统API对文件进行存储和删除。
1、配置
文件系统配置位于config/filesystems.php,默认配置如下:
代码如下 | 复制代码 |
return [ 'default' => 'local', 'local' => [ 'ftp' => [ 's3' => [ 'rackspace' => [ ], ]; |
从配置文件可以看出,Laravel默认的文件系统驱动是local,也就是本地驱动,默认的云存储是Amazon S3。我们可以修改这些默认配置。
所有支持的驱动及驱动详细配置定义在disks配置项中,在local驱动中使用root配置指定文件系统的根路径,即storage/app,这意味着如果使用local驱动,所有文件都会存放在该目录下。如果使用ftp驱动需要指定FTP主机、用户名和登录密码,此外还有一些额外配置,比如端口号、超时时间、加密方式等。同理使用s3或者rackspace也要填写相应的配置项。
由于我们使用local驱动,所以这里我们保持该配置文件不变即可。
2、基本使用
下面我们使用文件系统演示如何上传文件、获取文件、以及删除文件,我们将使用Storage门面提供的方法进行操作。
上传文件/获取文件
这里我们基于 HTTP 请求实例教程#上传文件这篇教程并对其上传方法postFileupload进行修改:
代码如下 | 复制代码 |
public function postFileupload(Request $request){ |
在上传处理逻辑中我们先保存文件到指定位置,然后判断保存后的文件是否存在,如果不存在则表明上传失败,否则显示上传文件内容。
比如我们测试上传图片,访问http://laravel.app:8000/request/fileupload,点击“选择文件”上传一张图片
下文我们来看一篇关于Laravel 5.1中定义事件、事件监听器以及触发事件例子,希望能够帮助到各位新手朋友的哦。这里我们基于之前基于模型+缓存对文章增删改查这篇文件对文章保存后缓存的处理做进一步优化。我们将文章保存(新建/修改)视为一个事件,将保存文章内容到缓存放到监听器中实现:
1、注册事件-监听器
首先我们需要在EventServiceProvider中注册事件与监听器之间的映射关系:
代码如下 | 复制代码 |
protected $listen = [ |
然后我们在项目根目录运行如下Artisan命令:
php artisan event:generate
该命令会在app/Events目录下生成PostSaved.php,在app/Listeners目录下生成SaveDataToCache.php。
2、定义事件类
接下来我们编辑事件类PostSaved如下:
代码如下 | 复制代码 |
<?php namespace App\Events; use App\Events\Event; class PostSaved extends Event /** /** |
我们在构造函数中注入一个Post实例传递给PostSaved。
3、定义监听器类
然后我们来定义监听器类SaveDataToCache,监听器类中使用handle方法接收事件实例并执行响应该事件的业务逻辑,这里就是将就接收到的Post实例保存到缓存中:
代码如下 | 复制代码 |
<?php namespace App\Listeners; use App\Events\PostSaved; class SaveDataToCache /** |
业务逻辑很简单:从注入的PostSaved中获取文章实例并将其保存到缓存,并将该操作记录到日志。
4、触发事件
最后我们来测试文章保存事件及其监听器。
要触发文章保存事件,可以使用Event门面提供的fire方法,在PostController中修改store方法如下:
代码如下 | 复制代码 |
public function store(Request $request) $post = new Post; Event::fire(new PostSaved($post)); return redirect()->route('post.show',['post'=>$post]); |
然后修改update方法如下:
代码如下 | 复制代码 |
public function update(Request $request, $id) $title = $request->input('title'); $post->title = $title; Event::fire(new PostSaved($post)); return redirect()->route('post.show',['post'=>$post]); |
在浏览器中访问http://laravel.app:8000/post/create,填写标题和文章内容:
点击提交页面跳转到文章详情页,此时去查看日志storage/logs/laravel.log,可以看到对应日志记录:
[2015-11-10 23:14:12] local.INFO: 保存文章到缓存成功! {"id":13,"title":"Test Event Add"}
说明已触发文章保存事件,监听器监听到事件后将其保存到缓存中并记录日志。
1、模式定义
Repository 是一个独立的层,介于领域层与数据映射层(数据访问层)之间。它的存在让领域层感觉不到数据访问层的存在,它提供一个类似集合的接口提供给领域层进行领域对象的访问。Repository 是仓库管理员,领域层需要什么东西只需告诉仓库管理员,由仓库管理员把东西拿给它,并不需要知道东西实际放在哪。
Repository 模式是架构模式,在设计架构时,才有参考价值。应用 Repository 模式所带来的好处,远高于实现这个模式所增加的代码。只要项目分层,都应当使用这个模式。
2、UML类图
3、示例代码
Post.php
<?php
namespace DesignPatterns\More\Repository;
/**
* Post 类
* @package DesignPatterns\Repository
*/
class Post
{
/**
* @var int
*/
private $id;
/**
* @var string
*/
private $title;
/**
* @var string
*/
private $text;
/**
* @var string
*/
private $author;
/**
* @var \DateTime
*/
private $created;
/**
* @param int $id
*/
public function setId($id)
{
$this->id = $id;
}
/**
* @return int
*/
public function getId()
{
return $this->id;
}
/**
* @param string $author
*/
public function setAuthor($author)
{
$this->author = $author;
}
/**
* @return string
*/
public function getAuthor()
{
return $this->author;
}
/**
* @param \DateTime $created
*/
public function setCreated($created)
{
$this->created = $created;
}
/**
* @return \DateTime
*/
public function getCreated()
{
return $this->created;
}
/**
* @param string $text
*/
public function setText($text)
{
$this->text = $text;
}
/**
* @return string
*/
public function getText()
{
return $this->text;
}
/**
* @param string $title
*/
public function setTitle($title)
{
$this->title = $title;
}
/**
* @return string
*/
public function getTitle()
{
return $this->title;
}
}
PostRepository.php
<?php
namespace DesignPatterns\More\Repository;
use DesignPatterns\More\Repository\Storage;
/**
* Post 对应的 Repository
* 该类介于数据实体层(Post) 和访问对象层(Storage)之间
*
* Repository 封装了持久化对象到数据存储器以及在展示层显示面向对象的视图操作
*
* Repository 还实现了领域层和数据映射层的分离和单向依赖
*
* PostRepository 类
* @package DesignPatterns\Repository
*/
class PostRepository
{
private $persistence;
public function __construct(Storage $persistence)
{
$this->persistence = $persistence;
}
/**
* 通过指定id返回Post对象
*
* @param int $id
* @return Post|null
*/
public function getById($id)
{
$arrayData = $this->persistence->retrieve($id);
if (is_null($arrayData)) {
return null;
}
$post = new Post();
$post->setId($arrayData['id']);
$post->setAuthor($arrayData['author']);
$post->setCreated($arrayData['created']);
$post->setText($arrayData['text']);
$post->setTitle($arrayData['title']);
return $post;
}
/**
* 保存指定对象并返回
*
* @param Post $post
* @return Post
*/
public function save(Post $post)
{
$id = $this->persistence->persist(array(
'author' => $post->getAuthor(),
'created' => $post->getCreated(),
'text' => $post->getText(),
'title' => $post->getTitle()
));
$post->setId($id);
return $post;
}
/**
* 删除指定的 Post 对象
*
* @param Post $post
* @return bool
*/
public function delete(Post $post)
{
return $this->persistence->delete($post->getId());
}
}
Storage.php
<?php
namespace DesignPatterns\More\Repository;
/**
* Storage接口
*
* 该接口定义了访问数据存储器的方法
* 具体的实现可以是多样化的,比如内存、关系型数据库、NoSQL数据库等等
*
* @package DesignPatterns\Repository
*/
interface Storage
{
/**
* 持久化数据方法
* 返回新创建的对象ID
*
* @param array() $data
* @return int
*/
public function persist($data);
/**
* 通过指定id返回数据
* 如果为空返回null
*
* @param int $id
* @return array|null
*/
public function retrieve($id);
/**
* 通过指定id删除数据
* 如果数据不存在返回false,否则如果删除成功返回true
*
* @param int $id
* @return bool
*/
public function delete($id);
}
MemoryStorage.php
<?php
namespace DesignPatterns\More\Repository;
use DesignPatterns\More\Repository\Storage;
/**
* MemoryStorage类
* @package DesignPatterns\Repository
*/
class MemoryStorage implements Storage
{
private $data;
private $lastId;
public function __construct()
{
$this->data = array();
$this->lastId = 0;
}
/**
* {@inheritdoc}
*/
public function persist($data)
{
$this->data[++$this->lastId] = $data;
return $this->lastId;
}
/**
* {@inheritdoc}
*/
public function retrieve($id)
{
return isset($this->data[$id]) ? $this->data[$id] : null;
}
/**
* {@inheritdoc}
*/
public function delete($id)
{
if (!isset($this->data[$id])) {
return false;
}
$this->data[$id] = null;
unset($this->data[$id]);
return true;
}
}
1、什么是命名空间
如果你只需要知道现代PHP特性中的一个,那就应该是命名空间。命名空间在PHP5.3.0中引入,其作用是按照一种虚拟的层次结构组织PHP代码,这种层次结构类似操作系统中文件系统的目录结构。命名空间是现代PHP组件生态的基础,现代的PHP组件框架代码都是放在各自全局唯一的厂商命名空间中,以免和其他厂商使用的常见类名冲突。
下面我来看看真实的PHP组件是如何使用命名空间的。Laravel框架中的Http组件用于管理HTTP请求和响应,这个组件用到了常见的类名,例如Request、Response,很多其他PHP组件也用到了这样的类名,既然其他PHP代码也用到了相同的类名,那怎么使用这个组件呢?其实我们可以放心使用,因为这个组件的代码放在了唯一的厂商命名空间Illuminate中。打开这个组件在GitHub中的仓库(https://github.com/laravel/framework/blob/master/src/Illuminate/Http/Response.php),找到Response.php文件:
第3行代码如下:
namespace Illuminate\Http;
这一行是PHP命名空间声明语句,声明命名空间的代码始终应该放在<?php标签后的第一行。通过这个命名空间的声明语句我们可以看到Response位于厂商命名空间Illuminate中(最顶层命名空间),我们还看到Response类在子命名空间Http中,你可以看下和Response.php文件在同一层级的其他文件,会发现它们都使用相同的命名空间声明语句。
命名空间的作用是封装和组织相关的PHP类,就像在文件系统中把相关的文件放在同一个目录中一样。PHP命名空间和操作系统的物理文件系统不同,这是一个虚拟概念,没必要和文件系统中的目录结构完全相同,虽然如此,但是大多数PHP组件为了兼容广泛使用的PSR-4自动加载标准,会把命名空间放到对应文件系统的子目录中。
2、为什么使用命名空间
前面已经提到过,我们的代码可能和其他开发者的代码使用相同的类名、接口名、函数或常量名,如果不使用命名空间,名称会起冲突,导致PHP执行出错。而使用命名空间将代码放到唯一的厂商命名空间,我们的代码就可以和其他开发者使用相同的类名、接口名、函数或常量名。
当然如果你开发的是小型个人项目,只有少量的依赖,类名冲突可能不是问题,但是如果在团队中工作,开发用到许多第三方依赖的大型项目,就要认真对待命名冲突问题,因为你无法控制项目依赖在全局命名空间中引入的类、接口、函数和常量,这也是为什么要使用命名空间的原因。
3、声明命名空间
每个PHP类、接口、函数和常量都在命名空间中,声明命名空间很简单,在<?php标签后的第一行声明,声明语句以namespace开头,随后是一个空格,然后是命名空间的名称,最后以;结尾。
命名空间经常用于设置顶层厂商名,比如我们设置厂商名为LaravelAcademy:
<?php
namespace LaravelAcademy;
在这个命名空间声明语句后声明的所有PHP类、接口、函数和常量都在LaravelAcademy命名空间中,而且和Laravel学院有某种关系。如果我们想组织学院用到的代码该怎么做呢?答案是使用子命名空间。
子命名空间的声明方式和前面的示例完全一样,唯一的区别是我们要使用\符号把命名空间和子命名空间分开,例如:
<?php
namespace LaravelAcademy\ModernPHP;
这个命名空间后的所有类、接口、函数和常量都位于LaravelAcademy\ModernPHP中。
在同一个命名空间中的类没必要在同一个PHP文件中声明,可以在PHP文件的顶部指定一个命名空间或子命名空间,此时,这个文件的代码就是该命名空间或子命名空间的一部分。因此我们可以在不同文件中编写属于同一个命名空间的多个类。
注:厂商命名空间是最顶层的命名空间,也是最重要的命名空间,用于识别品牌或组织,必须具有全局唯一性。子命名空间相对而言没那么重要,但是可以用于组织项目的代码。
4、导入和别名
在命名空间出现之前,PHP开发者使用Zend风格的类名解决命名冲突问题,这是一种类的命名方案,因Zend框架而流行,这种命名方案在PHP类名中使用下划线的方式表示文件系统的目录分隔符。这种约定有两个作用:其一,确保类名是唯一的;其二,原生的自动加载器会把类名中的下划线替换成文件系统的目录分隔符,从而确定文件的路径。例如,Zend_Cloud_DocumentService_Adapter_WindowsAzure_Query类对应的文件是Zend/Cloud/DocumentService/Adapter/WindowsAzure/Query.php。可以看出,这种命名有个缺点:类名特别长。
现代的PHP命名空间也有这个问题,例如上述Response类完整的全名是Illuminate\Http\Response,幸好,我们可以通过导入以及创建别名的方式来改变这一状况。
导入的意思是指,在每个PHP文件中告诉PHP想使用哪个命名空间、类、接口、函数和常量,导入后就不用使用全名了:
<?php
use Illuminate\Http\Response;
$response = new Response(‘Oops’, 400);
$response->send();
我们通过use关键字告诉PHP,我们想使用Illuminate\Http\Response类,我们只需要输入一次完全限定的类名,随后实例化Response的时候,无需使用完整的类名。
如果觉得这样的类名还是长,可以创建别名。创建别名指的是告诉PHP我要使用简单的名称引用导入的类、接口、函数或常量:
<?php
use Illuminate\Http\Response as Res;
$res = new Res(‘Oops’, 400);
$res->send();
从PHP 5.6开始还可以导入函数和常量,不过要调整use关键字的句法,如果要导入函数,需要使用use func:
<?php
use func Namespace\functionName
functionName();
如果想导入常量,可以使用use constant:
<?php
use constant Namespace\CONST_NAME;
echo CONST_NAME;
当然也支持别名,创建方式和类一样。
5、实用技巧
多重导入
如果想要在PHP文件中导入多个类、接口、函数或常量,需要在PHP文件的顶部使用多个use语句,PHP支持用简短的语法把多个use语句写成一行:
<?php
use Illuminate\Http\Request,
Illuminate\Http\Response;
但是为了可读性,建议不要这么写,还是一行写一个use语句比较好:
<?php
use Illuminate\Http\Request;
use Illuminate\Http\Response;
一个文件使用多个命名空间
PHP允许在一个文件中定义多个命名空间:
<?php
namespace Foo {
//声明类、接口、函数、常量
}
namespace Bar {
//声明类、接口、函数、常量
}
但这么做不好,违背了“一个文件一个类”的良好实践,因此不建议这么做。
全局命名空间
如果引用的类、接口、函数和常量没有指定命名空间,PHP假定引用的类、接口、函数和常量在当前的命名空间中。如果要使用其他命名空间的类、接口、函数或常量,需要使用完全限定的PHP类名(命名空间+类名)。
有些代码在全局命名空间中,没有命名空间,比如原生的Exception类就是这样。在命名空间中引用全局的代码时,需要在类、接口、函数或常量前加\符号:
<?php
namespace My\App;
class Foo {
public function doSomething() {
throw new \Exception();
}
}
自动加载
命名空间还为PHP-FIG制定的PSR-4自动加载标准奠定了坚实的基础,大多数现代的PHP组件都使用了这种自动加载模式,使用依赖管理器Composer可以自动加载项目的依赖,后续我们还会详细介绍Composer和PHP-FIG,现在你只需要知道没有命名空间,就没有现代的PHP生态系统和基于组件的新型架构,由此可见命名空间的重要性。
本文章来为各位介绍一篇关于php计算两个坐标(经度,纬度)之间距离的方法,希望这篇文章能够帮助到各位同学的哦。例子一
function distance($lat1, $lng1, $lat2, $lng2, $miles = true)
{
$pi80 = M_PI / 180;
$lat1 *= $pi80;
$lng1 *= $pi80;
$lat2 *= $pi80;
$lng2 *= $pi80;
$r = 6372.797;
$dlat = $lat2 - $lat1;
$dlng = $lng2 - $lng1;
$a = sin($dlat/2)*sin($dlat/2)+cos($lat1)*cos($lat2)*sin($dlng/2)*sin($dlng/2);
$c = 2 * atan2(sqrt($a), sqrt(1 - $a));
$km = $r * $c;
return ($miles ? ($km * 0.621371192) : $km);
}
例子二
/**
* 计算两个坐标之间的距离(米)
* @param float $fP1Lat 起点(纬度)
* @param float $fP1Lon 起点(经度)
* @param float $fP2Lat 终点(纬度)
* @param float $fP2Lon 终点(经度)
* @return int
*/
function distanceBetween($fP1Lat, $fP1Lon, $fP2Lat, $fP2Lon){
$fEARTH_RADIUS = 6378137;
//角度换算成弧度
$fRadLon1 = deg2rad($fP1Lon);
$fRadLon2 = deg2rad($fP2Lon);
$fRadLat1 = deg2rad($fP1Lat);
$fRadLat2 = deg2rad($fP2Lat);
//计算经纬度的差值
$fD1 = abs($fRadLat1 - $fRadLat2);
$fD2 = abs($fRadLon1 - $fRadLon2);
//距离计算
$fP = pow(sin($fD1/2), 2) +
cos($fRadLat1) * cos($fRadLat2) * pow(sin($fD2/2), 2);
return intval($fEARTH_RADIUS * 2 * asin(sqrt($fP)) + 0.5);
}
/**
* 百度坐标系转换成标准GPS坐系
* @param float $lnglat 坐标(如:106.426, 29.553404)
* @return string 转换后的标准GPS值:
*/
function BD09LLtoWGS84($fLng, $fLat){ // 经度,纬度
$lnglat = explode(',', $lnglat);
list($x,$y) = $lnglat;
$Baidu_Server = "http://api.map.baidu.com/ag/coord/convert?from=0&to=4&x={$x}&y={$y}";
$result = @file_get_contents($Baidu_Server);
$json = json_decode($result);
if($json->error == 0){
$bx = base64_decode($json->x);
$by = base64_decode($json->y);
$GPS_x = 2 * $x - $bx;
$GPS_y = 2 * $y - $by;
return $GPS_x.','.$GPS_y;//经度,纬度
}else
return $lnglat;
}
相关文章
- 下面小编来给大家演示几个php操作zip文件的实例,我们可以读取zip包中指定文件与删除zip包中指定文件,下面来给大这介绍一下。 从zip压缩文件中提取文件 代...2016-11-25
Jupyter Notebook读取csv文件出现的问题及解决
这篇文章主要介绍了JupyterNotebook读取csv文件出现的问题及解决,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教...2023-01-06- 如果我们需要安培Laravel4的话最php最低要求要在php5.3.7版本并且我们需要把mcrypt与openss这两个扩展开启才可以,具体步骤我们参考下文。 前面我们介绍我了 com...2016-11-25
- 有时我们接受或下载到的PSD文件打开是空白的,那么我们要如何来解决这个 问题了,下面一聚教程小伙伴就为各位介绍Photoshop打开PSD文件空白解决办法。 1、如我们打开...2016-09-14
- C#使用System.IO中的文件操作方法在Windows系统中处理本地文件相当顺手,这里我们还总结了在Oracle中保存文件的方法,嗯,接下来就来看看整理的C#操作本地文件及保存文件到数据库的基本方法总结...2020-06-25
- 这篇文章主要介绍了解决python 使用openpyxl读写大文件的坑,具有很好的参考价值,希望对大家有所帮助。一起跟随小编过来看看吧...2021-03-13
- 这篇文章主要介绍了C#实现HTTP下载文件的方法,包括了HTTP通信的创建、本地文件的写入等,非常具有实用价值,需要的朋友可以参考下...2020-06-25
- 这篇文章主要为大家详细介绍了SpringBoot实现excel文件生成和下载,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下...2021-02-09
- 复制代码 代码如下: <td> <a href="/member/life/edit_ppt/<?php echo $v->id;?>" class="btn">编辑</a> <a href="javascript:;" onclick="if(confirm('您确定删除这条记录?')){location.href='/member/life/d...2014-06-07
Laravel 调试工具 laravel-debugbar 打印日志消息
laravel-debugbar 调试工具的教程小编整理了几篇不错的教程,今天我们来看一篇Laravel 调试工具 laravel-debugbar 打印日志消息例子,希望文章对各位有帮助。 其实不...2016-11-25php无刷新利用iframe实现页面无刷新上传文件(1/2)
利用form表单的target属性和iframe 一、上传文件的一个php教程方法。 该方法接受一个$file参数,该参数为从客户端获取的$_files变量,返回重新命名后的文件名,如果上传失...2016-11-25Laravel 5.1中定义事件、事件监听器以及触发事件例子
下文我们来看一篇关于Laravel 5.1中定义事件、事件监听器以及触发事件例子,希望能够帮助到各位新手朋友的哦。 这里我们基于之前基于模型+缓存对文章增删改查这篇...2016-11-25- 要替换字符串中的内容我们只要利用php相关函数,如strstr,str_replace,正则表达式了,那么我们要替换目录所有文件的内容就需要先遍历目录再打开文件再利用上面讲的函数替...2016-11-25
- 又码了一个周末的代码,这次在做一些关于文件上传的东西。(PHP UPLOAD)小有收获项目是一个BT种子列表,用户有权限上传自己的种子,然后配合BT TRACK服务器把种子的信息写出来...2016-11-25
- 今天小编在这里就来给photoshop的这一款软件的使用者们来说下AI源文件转photoshop图像变模糊问题的解决教程,各位想知道具体解决方法的使用者们,那么下面就快来跟着小编...2016-09-14
- 最近由于项目的需要,需要动态的添加和删除table中的tr,感觉用JS可以实现,但是在网上找了一下,单纯的自己写JS,感觉太麻烦,而且也不好维护。于是想到了最近学的jQuery。这篇文章给大家用实例介绍了jQuery动态添加与删除tr行的方法,有需要的朋友们可以参考借鉴。...2016-10-20
- 这篇文章主要介绍了C++万能库头文件在vs中的安装步骤(图文),文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧...2021-02-23
- 步骤:Window -> PHP -> Editor -> Templates,这里可以设置(增、删、改、导入等)管理你的模板。新建文件注释、函数注释、代码块等模板的实例新建模板,分别输入Name、Description、Patterna)文件注释Name: 3cfileDescriptio...2013-10-04
- 这篇文章主要介绍了C#路径,文件,目录及IO常见操作,较为详细的分析并汇总了C#关于路径,文件,目录及IO常见操作,具有一定参考借鉴价值,需要的朋友可以参考下...2020-06-25
- 本篇文章主要说明的是与php文件上传的相关配置的知识点。PHP文件上传功能配置主要涉及php.ini配置文件中的upload_tmp_dir、upload_max_filesize、post_max_size等选项,下面一一说明。打开php.ini配置文件找到File Upl...2015-10-21