Commit 3b7aeda1 by LiuJunYi

导入会员

parent c4ff573e
<?php
namespace app\admin\controller;
use cocolait\extend\Excel;
use think\Exception;
use app\common\model\VipRelation as VipRelationModel;
class VipRelation extends AuthBase
{
/**
* 导入列表
*/
public function index()
{
$list = VipRelationModel::order('id','desc')->paginate();
return $this->fetch('',compact('list'));
}
public function excel()
{
try {
$file = request()->file('file')->getInfo();
//获取导入的数据
$data = Excel::excelFileToArray($file['tmp_name'], pathinfo($file['name'], PATHINFO_EXTENSION));
unset($data[0]);
$params = [];
foreach ($data as $k => $v) {
$arr = [
'nickname' => $v[0],
'mobile' => $v[1],
'wx_number' => $v[2],
'vip_expire' => str_replace('_','/',$v[3]),
'address' => $v[4],
];
array_push($params, $arr);
}
$model = new VipRelationModel();
$model->saveAll($params);
return json(['code' => 0, 'msg' => '导入成功']);
} catch (Exception $e) {
return json(['code' => 1, 'msg' => $e->getMessage()]);
}
}
}
\ No newline at end of file
{layout name="public/layout_main"}
<link rel="stylesheet" href="/static/layui/css/layui.css">
<section class="wrapper" >
<h3 style="margin-top: 15px;"><i class="fa fa-angle-right"></i> 用户管理</h3>
<!-- 分割线 -->
<hr>
<div class="row margin-bottom">
<div class="col-md-12">
<!--<form class="form-inline pull-left" method="GET" action="{:url('admin/user/index')}" >-->
<!--<div class="form-group margin-right">-->
<!--<input class="form-control" type="text" name="phone" id="phone" value="{:input('phone')}" placeholder="手机号"/>-->
<!--</div>-->
<!--<div class="form-group margin-right">-->
<!--<input class="form-control" type="text" name="nickname" id="nickname" value="{:input('nickname')}" placeholder="昵称"/>-->
<!--</div>-->
<!--<div class="form-group margin-right">-->
<!--<select name="is_vip" id="is_vip" class="form-control">-->
<!--<option value="">是否会员</option>-->
<!--<option value="1" {if condition="input('is_vip')==1"}selected{/if}>会员</option>-->
<!--<option value="0" {if condition="input('is_vip')==='0'"}selected{/if}>非会员</option>-->
<!--</select>-->
<!--</div>-->
<!--<div class="form-group margin-right">-->
<!--<label for="">注册时间:</label>-->
<!--<input class="form-control" type="date" name="start_time" id="start_time" value="{:input('start_time')}" placeholder="起始"/>-->
<!--&#45;&#45;-->
<!--<input class="form-control" type="date" name="end_time" id="end_time" value="{:input('end_time')}" placeholder="结束"/>-->
<!--</div>-->
<!--<button type="submit" class="btn btn-primary">搜索</button>-->
<!--</form>-->
<button type="button" class="layui-btn pull-right" id="excel"><i class="layui-icon"></i>导入会员列表</button>
</div>
</div>
<div class="row">
<div class="col-md-12">
<div class="table-responsive">
<table class="table table-bordered table-striped">
<thead>
<tr>
<th>ID</th>
<th>用户名</th>
<th>手机号</th>
<th>微信号</th>
<th>地址</th>
<th>会员到期时间</th>
<th>是否关联</th>
</tr>
</thead>
<tbody>
{foreach $list as $v}
<tr>
<td>{$v.id}</td>
<td>{$v.nickname}</td>
<td>{$v.mobile}</td>
<td>{$v.wx_number}</td>
<td>{$v.address}</td>
<td>{$v.vip_expire}</td>
<td>{$v.relation}</td>
</tr>
{/foreach}
</tbody>
</table>
</div>
</div>
</div>
<div class="row">
<div class="col-md-12">
{$list->render()}
</div>
</div>
</section>
<script src="/static/layui/layui.js"></script>
<script type="text/javascript">
layui.use(['jquery','layer','upload'],function () {
var $ = layui.jquery
,layer = layui.layer
,upload = layui.upload;
//指定允许上传的文件类型
upload.render({
elem: '#excel'
,url: "{:url('excel')}"
,accept: 'file' //普通文件
,done: function(res){
console.log(res)
}
});
});
</script>
...@@ -47,15 +47,9 @@ class Project extends Base ...@@ -47,15 +47,9 @@ class Project extends Base
if (input('?post.type')) $map['type'] = input('post.type/d'); if (input('?post.type')) $map['type'] = input('post.type/d');
//根据分类 //根据分类
if (input('?post.catalog_id')) $map['catalog_id'] = input('post.catalog_id'); if (input('?post.catalog_id')) $map['catalog_id'] = input('post.catalog_id');
//根据地区分类/国内国外
if (input('post.region_type')) {
$map['region_type'] = input('post.region_type');
} else {
if (input('?post.city')) $map['city'] = input('post.city');
}
//根据标签划分 //根据标签划分
if (input('?post.tags')) { if (input('?post.tags')) {
$tags = []; $tags = [];
$tagArray = json_decode(input('post.tags'), true); $tagArray = json_decode(input('post.tags'), true);
if ($tagArray) { if ($tagArray) {
if (count($tagArray) == 1) { if (count($tagArray) == 1) {
...@@ -74,6 +68,25 @@ class Project extends Base ...@@ -74,6 +68,25 @@ class Project extends Base
} }
$project = ProjectModel::all(function ($query) use ($map, $p, $page) { $project = ProjectModel::all(function ($query) use ($map, $p, $page) {
$query->where($map) $query->where($map)
->where(function ($query) {
//地域
if (input('level_1')) {
$query->where('level_1', input('level_1'));
}
if (input('level_2')) {
$query->where('level_2', input('level_2'));
}
if (input('level_3')) {
$query->where('level_3', input('level_3'));
}
if (input('sort') == 'id') {
$query->order('id', 'desc');
} elseif (input('price') == 'price') {
$query->order('price');
} else {
$query->order('sort', 'desc')->order('id', 'desc');
}
})
->order('sort', 'desc') ->order('sort', 'desc')
->page($p, $page); ->page($p, $page);
}); });
...@@ -218,6 +231,9 @@ class Project extends Base ...@@ -218,6 +231,9 @@ class Project extends Base
public function guides($p = 1, $page = 8) public function guides($p = 1, $page = 8)
{ {
$guides = GuideModel::all(function ($query) use ($p, $page) { $guides = GuideModel::all(function ($query) use ($p, $page) {
if(input('title')){
$query->where('title','like','%'.input('title').'%');
}
$query->order('sort', 'desc')->order('id', 'desc') $query->order('sort', 'desc')->order('id', 'desc')
->page($p, $page); ->page($p, $page);
}); });
...@@ -232,11 +248,11 @@ class Project extends Base ...@@ -232,11 +248,11 @@ class Project extends Base
* @param int pid 活动/商家id * @param int pid 活动/商家id
* @return json * @return json
*/ */
public function collect($pid = 0) public function collect($pid = 0)
{ {
if (empty($pid)) return ['code' => 1, 'msg' => '缺少参数pid']; if (empty($pid)) return ['code' => 1, 'msg' => '缺少参数pid'];
$uid = $this->userinfo[0]; $uid = $this->userinfo[0];
$data = UserCollectionModel::get(['uid' => $uid, 'pid' => $pid]); $data = UserCollectionModel::get(['uid' => $uid, 'pid' => $pid]);
$project = ProjectModel::get($pid); $project = ProjectModel::get($pid);
if (!$project) return ['code' => 1, 'msg' => '活动或该商家不存在']; if (!$project) return ['code' => 1, 'msg' => '活动或该商家不存在'];
if ($data) { if ($data) {
...@@ -271,10 +287,10 @@ class Project extends Base ...@@ -271,10 +287,10 @@ class Project extends Base
*/ */
public function searchCondition() public function searchCondition()
{ {
$data['type'] = [['id' => 1, 'name' => '活动'], ['id' => 2, 'name' => '商家']]; $data['type'] = [['id' => 1, 'name' => '活动'], ['id' => 2, 'name' => '商家']];
$data['catalog_id'] = collection(CatalogsModel::order('sort', 'desc')->select())->visible(['id', 'name'])->toArray(); $data['catalog_id'] = collection(CatalogsModel::order('sort', 'desc')->select())->visible(['id', 'name'])->toArray();
$data['city'] = collection(CitysModel::order('sort', 'desc')->select())->visible(['id', 'name'])->toArray(); $data['city'] = collection(CitysModel::order('sort', 'desc')->select())->visible(['id', 'name'])->toArray();
$data['tags'] = collection(TagsModel::order('sort', 'desc')->select())->visible(['id', 'name'])->toArray(); $data['tags'] = collection(TagsModel::order('sort', 'desc')->select())->visible(['id', 'name'])->toArray();
if (!$data) return ['code' => 1, 'msg' => '没有更多']; if (!$data) return ['code' => 1, 'msg' => '没有更多'];
array_unshift($data['type'], ['id' => '0', 'name' => "全部项目"]); array_unshift($data['type'], ['id' => '0', 'name' => "全部项目"]);
array_unshift($data['catalog_id'], ['id' => '0', 'name' => "全部分类"]); array_unshift($data['catalog_id'], ['id' => '0', 'name' => "全部分类"]);
...@@ -302,16 +318,16 @@ class Project extends Base ...@@ -302,16 +318,16 @@ class Project extends Base
// 是否过期 // 是否过期
$endTime = strtotime($project['sign_endtime']); $endTime = strtotime($project['sign_endtime']);
// 正常 // 正常
$project['status'] = 0; $project['status'] = 0;
$project['status_text'] = '立即报名'; $project['status_text'] = '立即报名';
if (strtotime($project['sign_endtime']) < time()) { if (strtotime($project['sign_endtime']) < time()) {
// 已过期 // 已过期
$project['status'] = 1; $project['status'] = 1;
$project['status_text'] = '预约下次'; $project['status_text'] = '预约下次';
} else { } else {
if (intval($project['sign_limits']) <= intval($project['sign_num'])) { if (intval($project['sign_limits']) <= intval($project['sign_num'])) {
// 已售罄 // 已售罄
$project['status'] = 2; $project['status'] = 2;
$project['status_text'] = '已售罄'; $project['status_text'] = '已售罄';
} }
} }
...@@ -366,7 +382,7 @@ class Project extends Base ...@@ -366,7 +382,7 @@ class Project extends Base
'pid' => 'require', 'pid' => 'require',
'expectation_time' => 'require', 'expectation_time' => 'require',
]); ]);
$res = $validate->check(input('post.')); $res = $validate->check(input('post.'));
if (!$res) return ['code' => 1, 'msg' => $validate->getError()]; if (!$res) return ['code' => 1, 'msg' => $validate->getError()];
if (!ProjectModel::get(input('post.pid'))) { if (!ProjectModel::get(input('post.pid'))) {
return ['code' => 1, 'msg' => '该活动不存在']; return ['code' => 1, 'msg' => '该活动不存在'];
......
<?php
namespace app\common\model;
class VipRelation extends BaseModel
{
// 设置当前模型对应的完整数据表名称
protected $table = 'mr_vip_relation';
protected $type = [
'vip_expire' => 'datetime',
];
public function getRelationAttr($v,$data)
{
$arr = ['未关联','已关联'];
return $arr[$data['is_relation']];
}
}
\ No newline at end of file
...@@ -21,7 +21,8 @@ ...@@ -21,7 +21,8 @@
"qiniu/php-sdk": "^7.1", "qiniu/php-sdk": "^7.1",
"jiguang/jmessage": "1.0.*", "jiguang/jmessage": "1.0.*",
"phpoffice/phpexcel": "^1.8", "phpoffice/phpexcel": "^1.8",
"topthink/think-captcha":"1.0.7" "topthink/think-captcha":"1.0.7",
"cocolait/excel": "^2.0"
}, },
"extra": { "extra": {
"think-path": "thinkphp" "think-path": "thinkphp"
......
# excel
PHP excel表格处理
## 链接
- 博客:http://www.mgchen.com
- github:https://github.com/cocolait
- gitee:http://gitee.com/cocolait
# 安装
```php
composer require cocolait/excel
```
# 版本要求
> PHP >= 5.3
# 使用说明
> 该扩展包适用于任何框架
# 使用案例
```php
<?php
// 加载包 如果你使用的框架已经支持自动加载composer了 这行那么就可以省略了
require "vendor/autoload.php"
// excel表格处理
// 导入Excel文件
$data = \cocolait\extend\Excel::importExcel('上传文件名称','上传文件目录');
// 导出Excel文件
$data = \cocolait\extend\Excel::exportExcel('文件名称','设置Excel表格第一行的显示','需要导出的所有数据');
// Excel转换Array
$data = \cocolait\extend\Excel::excelFileToArray('Excel文件全路径','文件后缀 默认是 xls');
```
\ No newline at end of file
{
"name": "cocolait/excel",
"description": "PHP excel表格处理",
"type": "library",
"homepage": "http://www.mgchen.com/",
"require": {
"php": ">=5.3.0",
"siriusphp/upload": "^2.1",
"phpoffice/phpexcel": "1.8.*"
},
"license": "Apache-2.0",
"authors": [
{
"name": "cocolait",
"email": "enkipen@qq.com"
}
],
"repositories": {
"packagist": {
"type": "composer",
"url": "https://packagist.phpcomposer.com"
}
},
"config": {
"preferred-install": "dist"
},
"minimum-stability": "stable",
"autoload" : {
"psr-4" : {
"cocolait\\extend\\" : "src/"
}
}
}
\ No newline at end of file
<?php
namespace cocolait\extend;
/**
* Excel表格处理
* Created by PhpStorm.
* User: Cocolait
* Date: 2018/05/17
* Time: 15:30
* 博 客:http://www.mgchen.com
*/
final class Excel{
/**
* 上传依赖包下载 composer require siriusphp/upload:^2.1
* 导入Excel文件
* @param string $input_Name 上传文件名称 示例 <input type="file" name="excel"/>
* @param string $dir 上传文件目录
* @return array
* @throws \Exception
*/
public static function importExcel($input_Name = 'excel',$dir = '') {
if (!$dir) {
$dir = "./uploads/excel" . "/" . date('Ymd');
}
if (!file_exists($dir)) {
if (!self::directory($dir)) {
return ['error'=>'1','msg'=>"无法创建目录:" . $dir];
};
}
//引入Composer第三方扩展上传类
$uploadHandler = new \Sirius\Upload\Handler($dir);
$uploadHandler->addRule('extension', ['allowed' => ['xls', 'xlsx']], '只能上传后缀为(.xls, .xlsx)文件');
$uploadHandler->addRule('size', ['max' => '10M'], '文件最大上传为10M');
$result = $uploadHandler->process($_FILES[$input_Name]);
if ($result->isValid()) {
try {
$result->confirm(); // 删除后缀.lock文件
$ext = substr(strrchr($result->name,'.'),1);
$filename = $dir . "/" . $result->name;
$data = self::excelFileToArray($filename, $ext);
if(count($data)==0 && $ext=='xlsx'){
return ['error' => 1,'msg'=>'内容为空或文件格式无效,建议转换为xls格式再次重试'];
}
//写入文件
return ['error'=>0,'msg'=> '上传成功 ^_^','url' => $filename,'file_name' => $result->name];
} catch (\Exception $e) {
$result->clear();
throw $e;
}
} else {
$message = $result->getMessages();
$error = '';
foreach ($message as $v) {
$error = $v->template;
}
return ['error' => 1,'msg'=> $error];
}
}
/**
* 导出Excel文件
* @param string $fileName 文件名称
* @param array $excelColumnItem 设置Excel表格第一行的显示
* @param array $data 载入表格的所有数据
* @return bool
* @throws \PHPExcel_Exception
* @throws \PHPExcel_Reader_Exception
* 运用实例
* $excelColumnItem = ['用户名','邮箱','个性签名'];
* $fileName = '后台用户信息表';
* $testData = Db::name('admin')->field(['username','email','signature'])->select();
* $data = [];
foreach ($testData as $k => $v){
$excelData[$k]['username'] = $v['username'];
$excelData[$k]['email'] = $v['email'];
$excelData[$k]['signature'] = $v['signature'];
}
外部调用 : \Cocolait\CpExcel::exportExcel($fileName,$excelColumnItem,$data);
生成表格
* 处理表格中 银行卡号或者数字长度问题 可用 chunk_split()函数进行处理,其实就是分割数字字符,不懂得自行查询php;
* chunk_split(string 要分割的字符 , int 分割位数, string 分割字符);
* 使用案例 chunk_split('201701061051',4," ");已4位数字分割,中间已空格隔开。
*/
public static function exportExcel($fileName = '', $excelColumnItem = [], $data = []){
$date = date("Y_m_d", time());
$fileName .= "_{$date}.xls";
$objPHPExcel = new \PHPExcel();
$objPHPExcel->getProperties();
// 设置表头
$key = ord("A");
foreach ($excelColumnItem as $v) {
$colum = chr($key);
$objPHPExcel->setActiveSheetIndex(0)->setCellValue($colum . '1', $v);
$objPHPExcel->setActiveSheetIndex(0)->setCellValue($colum . '1', $v);
$key += 1;
}
$column = 2;
$objActSheet = $objPHPExcel->getActiveSheet();
foreach ($data as $key => $rows) {// 行写入
$span = ord("A");
foreach ($rows as $keyName => $value) {// 列写入
$j = chr($span);
$objActSheet->setCellValue($j . $column, $value);
$span ++;
}
$column ++;
}
$fileName = iconv("utf-8", "gb2312", $fileName);
// 重命名表
$objPHPExcel->setActiveSheetIndex(0);
header('Content-Type: application/vnd.ms-excel');
header("Content-Disposition: attachment;filename=\"$fileName\"");
header('Cache-Control: max-age=0');
$objWriter = \PHPExcel_IOFactory::createWriter($objPHPExcel, 'Excel5');
$objWriter->save('php://output');//文件通过浏览器下载
return true;
}
/**
* Excel文件转换为数组数据
* @param String $filePath Excel文件全路径[文件名称]
* @param string $exts 文件后缀 默认是 xls
* @return array
* @throws \PHPExcel_Exception
*/
public static function excelFileToArray($filePath, $exts = 'xls')
{
if (!in_array($exts,['xls','xlsx'])) {
return ['error' => 1, 'msg' => '只支持‘xls,xlsx’类型的格式'];
}
// 检测后缀,实例化具体操作类
if ($exts == 'xls') {
$PHPReader = new \PHPExcel_Reader_Excel5();
} else if ($exts == 'xlsx') {
//偶尔不wps另存为的xlsx文件
$PHPReader = new \PHPExcel_Reader_Excel2007();
}
// 读取Excel文件
$PHPExcel = $PHPReader->load($filePath);
// 获取表中的第一个工作表,如果要获取第二个,把0改为1,依次类推
$currentSheet = $PHPExcel->getSheet(0);
// 获取总列数
$allColumn = $currentSheet->getHighestColumn();
// 获取总行数
$allRow = $currentSheet->getHighestRow();
//循环读取数据,默认编码是utf8
$data = [];
// 循环获取表中的数据,$currentRow表示当前行,从哪行开始读取数据,索引值从0开始
for($currentRow = 1;$currentRow<=$allRow;$currentRow++)
{
// 从哪列开始,A表示第一列
for($currentColumn='A';$currentColumn<=$allColumn;$currentColumn++)
{
// 数据坐标
$address = $currentColumn.$currentRow;
// 获取单元格的值
$v = $currentSheet->getCell($address)->getValue();
// 匹配http/https
$preg_url = "/^((http|https):\/\/)+[\w-_.]+(\/[\w-_]+)*\/?$/";
// 过滤时间
if (preg_match("/^[0-9]{5}.[0-9]{1,20}$/",$v) && strrpos($v,'.') && \PHPExcel_Shared_Date::isDateTime($currentSheet->getCell($address))) {
// 匹配时间并且进行格式化
$data[$currentRow-1][$currentColumn] = gmdate("Y/m/d H:i", \PHPExcel_Shared_Date::ExcelToPHP($v));
} else if (preg_match($preg_url,$v)) {
// 匹配url
$data[$currentRow-1][$currentColumn] = "<a href='$v'>$v</a>";
} else {
$data[$currentRow-1][$currentColumn] = $v;
}
}
}
//处理空白数组
$res = [];
if ($data) {
foreach($data as $k => $v) {
$res[] = array_values($v);
}
}
return $res;
}
/**
* 抛出异常
* @param $error
* @throws \Exception
*/
protected static function throwException($error)
{
throw new \Exception($error);
}
/**
* 递归创建目录
* @param $dir
* @return bool
*/
protected static function directory($dir)
{
return is_dir ($dir) or self::directory(dirname($dir)) and mkdir ($dir, 0777);
}
}
\ No newline at end of file
...@@ -374,10 +374,14 @@ class ClassLoader ...@@ -374,10 +374,14 @@ class ClassLoader
$first = $class[0]; $first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) { if (isset($this->prefixLengthsPsr4[$first])) {
foreach ($this->prefixLengthsPsr4[$first] as $prefix => $length) { $subPath = $class;
if (0 === strpos($class, $prefix)) { while (false !== $lastPos = strrpos($subPath, '\\')) {
foreach ($this->prefixDirsPsr4[$prefix] as $dir) { $subPath = substr($subPath, 0, $lastPos);
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $length))) { $search = $subPath . '\\';
if (isset($this->prefixDirsPsr4[$search])) {
$pathEnd = DIRECTORY_SEPARATOR . substr($logicalPathPsr4, $lastPos + 1);
foreach ($this->prefixDirsPsr4[$search] as $dir) {
if (file_exists($file = $dir . $pathEnd)) {
return $file; return $file;
} }
} }
......
Copyright (c) 2016 Nils Adermann, Jordi Boggiano Copyright (c) Nils Adermann, Jordi Boggiano
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal
......
...@@ -9,6 +9,9 @@ return array( ...@@ -9,6 +9,9 @@ return array(
'think\\composer\\' => array($vendorDir . '/topthink/think-installer/src'), 'think\\composer\\' => array($vendorDir . '/topthink/think-installer/src'),
'think\\captcha\\' => array($vendorDir . '/topthink/think-captcha/src'), 'think\\captcha\\' => array($vendorDir . '/topthink/think-captcha/src'),
'think\\' => array($baseDir . '/thinkphp/library/think'), 'think\\' => array($baseDir . '/thinkphp/library/think'),
'cocolait\\extend\\' => array($vendorDir . '/cocolait/excel/src'),
'Sirius\\Validation\\' => array($vendorDir . '/siriusphp/validation/src'),
'Sirius\\Upload\\' => array($vendorDir . '/siriusphp/upload/src'),
'Qiniu\\' => array($vendorDir . '/qiniu/php-sdk/src/Qiniu'), 'Qiniu\\' => array($vendorDir . '/qiniu/php-sdk/src/Qiniu'),
'JMessage\\' => array($vendorDir . '/jiguang/jmessage/src/JMessage'), 'JMessage\\' => array($vendorDir . '/jiguang/jmessage/src/JMessage'),
); );
...@@ -18,6 +18,15 @@ class ComposerStaticInit6a7a2aa86217a80f5a5c162d0365f49c ...@@ -18,6 +18,15 @@ class ComposerStaticInit6a7a2aa86217a80f5a5c162d0365f49c
'think\\captcha\\' => 14, 'think\\captcha\\' => 14,
'think\\' => 6, 'think\\' => 6,
), ),
'c' =>
array (
'cocolait\\extend\\' => 16,
),
'S' =>
array (
'Sirius\\Validation\\' => 18,
'Sirius\\Upload\\' => 14,
),
'Q' => 'Q' =>
array ( array (
'Qiniu\\' => 6, 'Qiniu\\' => 6,
...@@ -41,6 +50,18 @@ class ComposerStaticInit6a7a2aa86217a80f5a5c162d0365f49c ...@@ -41,6 +50,18 @@ class ComposerStaticInit6a7a2aa86217a80f5a5c162d0365f49c
array ( array (
0 => __DIR__ . '/../..' . '/thinkphp/library/think', 0 => __DIR__ . '/../..' . '/thinkphp/library/think',
), ),
'cocolait\\extend\\' =>
array (
0 => __DIR__ . '/..' . '/cocolait/excel/src',
),
'Sirius\\Validation\\' =>
array (
0 => __DIR__ . '/..' . '/siriusphp/validation/src',
),
'Sirius\\Upload\\' =>
array (
0 => __DIR__ . '/..' . '/siriusphp/upload/src',
),
'Qiniu\\' => 'Qiniu\\' =>
array ( array (
0 => __DIR__ . '/..' . '/qiniu/php-sdk/src/Qiniu', 0 => __DIR__ . '/..' . '/qiniu/php-sdk/src/Qiniu',
......
/vendor/
composer.phar
composer.lock
examples/config.php
The MIT License (MIT)
Copyright (c) 2015 极光推送/IM JPush/JMesage
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
# JMessage API PHP Client
这是 JMessage REST API 的 PHP 版本封装开发包,是由极光推送官方提供的,一般支持最新的 API 功能。
对应的 REST API 文档: https://docs.jiguang.cn/jmessage/server/rest_api_im/
> 支持的 PHP 版本: 5.4 ~ 5.6.x, 7
## Installation
#### 使用 Composer 安装
- 在项目中的 `composer.json` 文件中添加 jmessage 依赖:
```json
"require": {
"jiguang/jmessage": "1.0.*"
}
```
- 执行 `$ php composer.phar install``$ composer install` 进行安装。
#### 直接下载源码安装
> 直接下载源代码也是一种安装 SDK 的方法,不过因为有版本更新的维护问题,所以这种安装方式**十分不推荐**,但由于种种原因导致无法使用 Composer,所以我们也提供了这种情况下的备选方案。
- 下载源代码包,解压到项目中
- 在项目中引入 autoload(在源码根目录下):
```php
require 'path_to_sdk/autoload.php';
```
## Usage
* [JMessage Client](https://github.com/jpush/jmessage-api-php-client/blob/master/docs/GUIDE.md#jmessage-client)
* [User 用户](https://github.com/jpush/jmessage-api-php-client/blob/master/docs/GUIDE.md#user-用户)
* [Admin 管理员](https://github.com/jpush/jmessage-api-php-client/blob/master/docs/GUIDE.md#admin-管理员)
* [Blacklist 黑名单](https://github.com/jpush/jmessage-api-php-client/blob/master/docs/GUIDE.md#blacklist-黑名单)
* [Group 群组](https://github.com/jpush/jmessage-api-php-client/blob/master/docs/GUIDE.md#group-群组)
* [Friend 好友](https://github.com/jpush/jmessage-api-php-client/blob/master/docs/GUIDE.md#friend-好友)
* [Resource 媒体资源](https://github.com/jpush/jmessage-api-php-client/blob/master/docs/GUIDE.md#resource-媒体资源)
* [发送消息](https://github.com/jpush/jmessage-api-php-client/blob/master/docs/GUIDE.md#发送消息)
* [跨应用](https://github.com/jpush/jmessage-api-php-client/blob/master/docs/CROSS.md#cross-跨应用)
## Examples
**注意: 这只是使用样例, 不应该直接用于实际环境中!!**
在项目的 [examples](https://github.com/jpush/jmessage-api-php-client/tree/master/examples) 文件夹中有简单的使用示例代码, 开发者可以参考其中的样例快速了解该库的使用方法。
**注:所下载的样例代码不可马上使用,需要在 `examples/config.php` 文件中填入相关的必要参数,或者设置相关环境变量,不进行这个操作则示例运行会失败。**另外为保护开发者隐私 `examples/config.php` 文件不在版本控制中,需要使用如下命令手动复制:
```php
$ cp examples/config.php.example examples/config.php
```
**示例简单使用方法**
若要运行 friend_examples.php 中的示例代码:
```bash
# 假定当前目录为 JMessage 源码所在的根目录
$ php examples/friend_examples.php
```
> 当然也可编辑相关的示例文件,更改参数查看执行效果
## ErrorCode
JMessage 服务器端报的错误码。有可能出现在返回值中,可在这里查询含义: https://docs.jiguang.cn/jmessage/client/im_errorcode_server/
## Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/jpush/jmessage-api-php-client.
## License
The library is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
<?php
function classLoader($class)
{
$path = str_replace('\\', DIRECTORY_SEPARATOR, $class);
$file = __DIR__ . '/src/' . $path . '.php';
if (file_exists($file)) {
require_once $file;
}
}
spl_autoload_register('classLoader');
{
"name": "jiguang/jmessage",
"type": "library",
"version": "1.0.4",
"description": "JMessage's officially supported PHP client library for accessing JMessage APIs.",
"keywords": ["jiguang", "jmessage", "API Client"],
"homepage": "https://github.com/jpush/jmessage-api-php-client",
"license": "MIT",
"authors": [
{
"name": "JiGuang",
"email": "support@jpush.cn",
"homepage": "https://www.jiguang.cn"
}
],
"require": {
"php": ">=5.4",
"ext-curl": "*"
},
"autoload" : {
"psr-4": {"JMessage\\": "src/JMessage/"}
}
}
<?php
require __DIR__ . '/../config.php';
use JMessage\IM\Admin;
$admin = new Admin($jm);
$info = [
'username' => 'admin',
'password' => 'password'
];
$response = $admin->register($info);
print_r($response);
<?php
require __DIR__ . '/../config.php';
use JMessage\IM\Admin;
$admin = new Admin($jm);
$response = $admin->listAll();
print_r($response);
<?php
require __DIR__ . '/../vendor/autoload.php';
use JMessage\JMessage;
$appKey = 'xxxx';
$masterSecret = 'xxxx';
$jm = new JMessage($appKey, $masterSecret);
<?php
require __DIR__ . '/config.php';
use JMessage\IM\Friend;
$friend = new Friend($jm);
$user = 'user_0';
$friends = ['user_1', 'user_2'];
echo "list friends: \n";
$response = $friend->listAll($user);
print_r($response);
echo "\n";
echo "add friends: \n";
$response = $friend->add($user, $friends);
print_r($response);
echo "\n";
echo "list friends: \n";
$response = $friend->listAll($user);
print_r($response);
echo "\n";
echo "update notename of friends: \n";
$response = $friend->updateNotename($user, [
[
'username' => 'user_1',
'note_name' => 'user_1_alias',
'others' => 'good friend'
], [
'username' => 'user_2',
'note_name' => 'user_2_alias',
'others' => 'normal friend'
]
]);
print_r($response);
echo "\n";
echo "list friends: \n";
$response = $friend->listAll($user);
print_r($response);
echo "\n";
echo "remove friends: \n";
$response = $friend->remove($user, $friends);
print_r($response);
echo "\n";
<?php
require __DIR__ . '/config.php';
use JMessage\IM\Group;
$group = new Group($jm);
$owner = 'user_0';
$name = 'jiguang';
// $members = ['user_1', 'user_2', 'user_3'];
$members = [];
$mems = ['user_4', 'user_5'];
$desc = 'jiguang gtoup';
echo "create group: \n";
$response = $group->create($owner, $name, $desc, $members);
print_r($response);
echo "\n";
$gid = $response['body']['gid'];
echo "show group: \n";
$response = $group->show($gid);
print_r($response);
echo "\n";
echo "update group: \n";
$name = 'new jiguang';
$desc = 'new jiguang gtoup';
$response = $group->update($gid, $name, $desc);
print_r($response);
echo "\n";
echo "group list: \n";
$response = $group->listAll(0, 10);
print_r($response);
echo "\n";
#### members start
echo "list members in group: \n";
$response = $group->members($gid);
print_r($response);
echo "\n";
echo "add members to group: \n";
$response = $group->addMembers($gid, $mems);
print_r($response);
echo "\n";
echo "list members in group: \n";
$response = $group->members($gid);
print_r($response);
echo "\n";
echo "remove members from group: \n";
$response = $group->removeMembers($gid, $mems);
print_r($response);
echo "\n";
echo "list members in group: \n";
$response = $group->members($gid);
print_r($response);
echo "\n";
#### members end
echo "delete group: \n";
$response = $group->delete($gid);
print_r($response);
echo "\n";
<?php
require __DIR__ . '/config.php';
use JMessage\IM\Report;
$report = new Report($jm);
$response = $report->getMessages(0, 100);
print_r($response);
$response = $report->getUserMessages('user_0', 0, 100);
print_r($response);
<?php
require __DIR__ . '/config.php';
use JMessage\IM\Resource;
$rescource = new Resource($jm);
$image = __DIR__ . '/jiguang.png';
echo "upload image: \n";
$response = $rescource->upload('image', $image);
print_r($response);
echo "\n";
echo "upload file: \n";
$response = $rescource->upload('file', $image);
print_r($response);
echo "\n";
$mediaId = $response['body']['media_id'];
echo "download file: \n";
$response = $rescource->download($mediaId);
print_r($response);
echo "\n";
<?php
require __DIR__ . '/../config.php';
use JMessage\IM\Blacklist;
$blacklist = new Blacklist($jm);
$user = 'user_0';
echo "add blacklist: \n";
$response = $blacklist->add($user, ['user_1']);
print_r($response);
echo "\n";
echo "get blacklists: \n";
$response = $blacklist->listAll($user);
print_r($response);
echo "\n";
echo "remove blacklist: \n";
$response = $blacklist->remove($user, ['user_1']);
print_r($response);
echo "\n";
echo "get blacklists: \n";
$response = $blacklist->listAll($user);
print_r($response);
echo "\n";
<?php
require __DIR__ . '/../config.php';
use JMessage\IM\User;
$user = new User($jm);
$username = 'user_0';
echo "add single nodisturb: \n";
$response = $user->addSingleNodisturb($username, ['user_1']);
print_r($response);
echo "\n";
echo "remove single nodisturb: \n";
$response = $user->removeSingleNodisturb($username, ['user_1']);
print_r($response);
echo "\n";
echo "open global nodisturb: \n";
$response = $user->openGlobalNodisturb($username);
print_r($response);
echo "\n";
echo "close global nodisturb: \n";
$response = $user->closeGlobalNodisturb($username);
print_r($response);
echo "\n";
// 自定义免打扰的设置参数比较复杂,建议使用上面所述的 6 种方式设置免打扰。
// echo "custom nodisturb setting: \n";
// $touser = 'user';
// $user0 = 'user_0';
// $user1 = 'user_1';
// $user2 = 'user_2';
// $user3 = 'user_3';
// $gid0 = '10000';
// $gid1 = '10001';
// $gid2 = '10002';
// $gid3 = '10003';
// $options = [
// "single" => [
// "add" => [$user0, $user1],
// "remove" => [$user2, $user3],
// ],
// "group" => [
// "add" => [$gid0, $gid1],
// "remove" => [$gid2, $gid3],
// ],
// "global" => 1
// ];
// $response = $user->nodisturb($touser, $options);
// print_r($response);
// echo "\n";
<?php
require __DIR__ . '/../config.php';
use JMessage\IM\User;
$user = new User($jm);
$users = [
['username' => 'user_0', 'password' => 'password'],
['username' => 'user_1', 'password' => 'password'],
['username' => 'user_2', 'password' => 'password'],
['username' => 'user_3', 'password' => 'password'],
['username' => 'user_4', 'password' => 'password'],
['username' => 'user_5', 'password' => 'password'],
['username' => 'user_6', 'password' => 'password'],
['username' => 'user_7', 'password' => 'password'],
['username' => 'user_8', 'password' => 'password'],
['username' => 'user_9', 'password' => 'password'],
['username' => 'user_10', 'password' => 'password']
];
$response = $user->batchRegister($users);
print_r($response);
$username = 'username_20';
$password = 'password';
$response = $user->register($username, $password);
print_r($response);
<?php
require __DIR__ . '/../config.php';
use JMessage\IM\User;
$user = new User($jm);
$username = 'user_0';
echo "get users list: \n";
$response = $user->listAll(0, 100);
print_r($response);
echo "\n";
echo "get user info: \n";
$response = $user->show($username);
print_r($response);
echo "\n";
echo "update user info: \n";
$response = $user->update($username, ['nickname' => 'user_nickname_0', 'gender' => 2]);
print_r($response);
echo "\n";
echo "get user stat: \n";
$response = $user->stat($username);
print_r($response);
echo "\n";
echo "change user password: \n";
$response = $user->updatePassword($username, 'password_0');
print_r($response);
echo "\n";
// echo "delete user: \n";
// $response = $user->delete('user_10');
// print_r($response);
// echo "\n";
echo "get user's groups: \n";
$response = $user->groups($username);
print_r($response);
echo "\n";
<?php
namespace JMessage\Cross;
use JMessage\IM;
class Blacklist extends IM {
const BASE_URI = 'https://api.im.jpush.cn/v1/cross/users/';
public function add($user, $appKey, array $usernames) {
$body = [[
'appKey' => $appKey,
'usernames' => $usernames
]];
return $this->batchAdd($user, $body);
}
public function batchAdd($user, array $options) {
$uri = self::BASE_URI . $user . '/blacklist';
$body = $options;
$response = $this->put($uri, $body);
return $response;
}
public function remove($user, $appKey, array $usernames) {
$body = [[
'appKey' => $appKey,
'usernames' => $usernames
]];
return $this->batchRemove($user, $body);
}
public function batchRemove($user, array $options) {
$uri = self::BASE_URI . $user . '/blacklist';
$body = $options;
$response = $this->del($uri, $body);
return $response;
}
public function listAll($user) {
$uri = self::BASE_URI . $user . '/blacklist';
$response = $this->get($uri);
return $response;
}
}
<?php
namespace JMessage\Cross;
use JMessage\IM;
class Friend extends IM {
const BASE_URI = 'https://api.im.jpush.cn/v1/cross/users/';
public function add($user, $appKey, array $friendnames) {
$uri = self::BASE_URI . $user . '/friends';
$body = [
'appKey' => $appKey,
'users' => $friendnames
];
$response = $this->post($uri, $body);
return $response;
}
public function remove($user, $appKey, array $friendnames) {
$uri = self::BASE_URI . $user . '/friends';
$body = [
'appKey' => $appKey,
'users' => $friendnames
];
$response = $this->del($uri, $body);
return $response;
}
public function updateNotename($user, $appKey, $friendname, array $options) {
$body = [
'appKey' => $appKey,
'username' => $friendname
];
if (isset($options['note_name'])) {
$body['note_name'] = $options['note_name'];
}
if (isset($options['others'])) {
$body['others'] = $options['others'];
}
return $this->batchUpdateNotename($user, [$body]);
}
public function batchUpdateNotename($user, array $options) {
$uri = self::BASE_URI . $user . '/friends';
$response = $this->put($uri, $body);
return $response;
}
}
<?php
namespace JMessage\Cross;
use JMessage\IM;
class Member extends IM {
const BASE_URI = 'https://api.im.jpush.cn/v1/cross/groups/';
public function add($gid, $appKey, array $usernames) {
$body = [[
'appKey' => $appKey,
'add' => $usernames
]];
return $this->update($gid, $body);
}
public function remove($gid, $appKey, array $usernames) {
$body = [[
'appKey' => $appKey,
'remove' => $usernames
]];
return $this->update($gid, $body);
}
public function update($gid, array $options) {
$uri = self::BASE_URI . $gid . '/members';
$body = $options;
$response = $this->post($uri, $body);
return $response;
}
public function listAll($gid) {
$uri = self::BASE_URI . $gid . '/members';
$response = $this->get($uri);
return $response;
}
}
<?php
namespace JMessage\Cross;
use JMessage\IM;
class Nodisturb extends IM {
const BASE_URI = 'https://api.im.jpush.cn/v1/cross/users/';
public function single($user, $appKey, array $options) {
$body = [ 'appKey' => $appKey ];
if (!isset($options['add'])) {
$body['single']['add'] = $options['add'];
}
if (!isset($options['remove'])) {
$body['single']['remove'] = $options['remove'];
}
return $this->nodisturb($user, [$body]);
}
public function group($user, $appKey, array $options) {
$body = [ 'appKey' => $appKey ];
if (!isset($options['add'])) {
$body['group']['add'] = $options['add'];
}
if (!isset($options['remove'])) {
$body['group']['remove'] = $options['remove'];
}
return $this->nodisturb($user, [$body]);
}
public function nodisturb($user, array $options ) {
$uri = self::BASE_URI . $user . '/nodisturb';
$body = $options;
$response = $this->post($uri, $body);
return $response;
}
}
<?php
namespace JMessage;
class Http {
private $client;
private static $_instance = null;
public function get($uri, array $query = []) {
if (!empty($query)) {
$uri = $uri . '?' . http_build_query($query);
}
return self::request($this->client, 'GET', $uri);
}
public function post($uri, array $body = []) {
return self::request($this->client, 'POST', $uri, $body);
}
public function put($uri, array $body = []) {
return self::request($this->client, 'PUT', $uri, $body);
}
public function delete($uri, array $body = []) {
return self::request($this->client, 'DELETE', $uri, $body);
}
public function upload($uri, array $body = []) {
$headers = [
'Content-Type: multipart/form-data',
'Connection: Keep-Alive'
];
return self::request($this->client, 'UPLOAD', $uri, $body, $headers);
}
public static function getInstance($client) {
if (is_null(self::$_instance) || !(self::$_instance instanceof self)) {
self::$_instance = new self($client);
}
return self::$_instance;
}
private function __construct($client) {
$this->client = $client;
}
private function __clone() {}
private static function request($client, $method, $uri, array $body = [], array $headers = []) {
$default_headers = [
'Content-Type: application/json',
'Connection: Keep-Alive'
];
$method = strtoupper($method);
$ch = curl_init();
$options = array(
CURLOPT_RETURNTRANSFER => true,
CURLOPT_HEADER => true,
CURLOPT_HTTPHEADER => (empty($headers) ? $default_headers : $headers),
CURLOPT_USERAGENT => 'JMessage-Api-PHP-Client',
CURLOPT_CONNECTTIMEOUT => 20,
CURLOPT_TIMEOUT => 120,
CURLOPT_HTTPAUTH => CURLAUTH_BASIC,
CURLOPT_USERPWD => $client->getAuth(),
CURLOPT_URL => $uri,
CURLOPT_CUSTOMREQUEST => ('UPLOAD' == $method) ? 'POST' : $method
);
if (!empty($body)) {
if ('UPLOAD' == $method) {
if (class_exists('\CURLFile')) {
$options[CURLOPT_SAFE_UPLOAD] = true;
$options[CURLOPT_POSTFIELDS] = ['filename' => new \CURLFile($body['path'])];
} else {
# TODO
if (defined('CURLOPT_SAFE_UPLOAD')) {
$options[CURLOPT_SAFE_UPLOAD] = false;
$options[CURLOPT_POSTFIELDS] = '';
}
}
} else {
$options[CURLOPT_POSTFIELDS] = json_encode($body);
}
}
curl_setopt_array($ch, $options);
$output = curl_exec($ch);
if($output === false) {
return "Error Code:" . curl_errno($ch) . ", Error Message:".curl_error($ch);
} else {
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
$header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
$header_text = substr($output, 0, $header_size);
$body = substr($output, $header_size);
$headers = array();
foreach (explode("\r\n", $header_text) as $i => $line) {
if (!empty($line)) {
if ($i === 0) {
$headers[0] = $line;
} else if (strpos($line, ": ")) {
list ($key, $value) = explode(': ', $line);
$headers[$key] = $value;
}
}
}
$response['headers'] = $headers;
$response['body'] = json_decode($body, true);
$response['http_code'] = $httpCode;
}
curl_close($ch);
return $response;
}
}
<?php
namespace JMessage;
use JMessage\Http;
class IM {
private $client;
public function __construct($client) {
$this->client = Http::getInstance($client);
}
public function get($uri, array $query = []) {
return $this->client->get($uri, $query);
}
public function post($uri, array $body = []) {
return $this->client->post($uri, $body);
}
public function put($uri, array $body = []) {
return $this->client->put($uri, $body);
}
public function del($uri, array $body = []) {
return $this->client->delete($uri, $body);
}
protected function getClient() {
return $this->client;
}
}
<?php
namespace JMessage\IM;
use JMessage\IM;
class Admin extends IM {
const BASE_URI = 'https://api.im.jpush.cn/v1/admins/';
public function register(array $admin) {
$uri = self::BASE_URI;
$body = $admin;
$response = $this->post($uri, $body);
return $response;
}
public function listAll($start = 0, $count = 10) {
$uri = self::BASE_URI;
$query = [
'start' => $start,
'count' => $count
];
$response = $this->get($uri, $query);
return $response;
}
}
<?php
namespace JMessage\IM;
use JMessage\IM;
class Blacklist extends IM {
const BASE_URI = 'https://api.im.jpush.cn/v1/users/';
public function add($user, array $usernames) {
$uri = self::BASE_URI . $user . '/blacklist';
$body = $usernames;
$response = $this->put($uri, $body);
return $response;
}
public function remove($user, array $usernames) {
$uri = self::BASE_URI . $user . '/blacklist';
$body = $usernames;
$response = $this->del($uri, $body);
return $response;
}
public function listAll($user) {
$uri = self::BASE_URI . $user . '/blacklist';
$response = $this->get($uri);
return $response;
}
}
<?php
namespace JMessage\IM;
use JMessage\IM;
class Friend extends IM {
const BASE_URI = 'https://api.im.jpush.cn/v1/users/';
public function add($user, array $friends) {
$uri = self::BASE_URI . $user . '/friends';
$body = $friends;
$response = $this->post($uri, $body);
return $response;
}
public function remove($user, array $friends) {
$uri = self::BASE_URI . $user . '/friends';
$body = $friends;
$response = $this->del($uri, $body);
return $response;
}
public function updateNotename($user, array $options) {
$uri = self::BASE_URI . $user . '/friends';
$body = $options;
$response = $this->put($uri, $body);
return $response;
}
public function listAll($user) {
$uri = self::BASE_URI . $user . '/friends';
$response = $this->get($uri);
return $response;
}
}
<?php
namespace JMessage\IM;
use JMessage\IM;
class Group extends IM {
const BASE_URI = 'https://api.im.jpush.cn/v1/groups/';
public function create($owner, $name, $desc, array $members = []) {
$uri = self::BASE_URI;
$body = [
'owner_username' => $owner,
'name' => $name,
'desc' => $desc,
'members_username' => $members
];
$response = $this->post($uri, $body);
return $response;
}
public function show($gid) {
$uri = self::BASE_URI . $gid;
$response = $this->get($uri);
return $response;
}
public function update($gid, $name = null, $desc = null) {
$uri = self::BASE_URI . $gid;
$body = [];
if (!is_null($name)) { $body['name'] = $name; }
if (!is_null($desc)) { $body['desc'] = $desc; }
$response = $this->put($uri, $body);
return $response;
}
public function delete($gid) {
$uri = self::BASE_URI . $gid;
$response = $this->del($uri);
return $response;
}
public function listAll($start = 0, $count = 20) {
$uri = self::BASE_URI;
$query = [
'start' => $start,
'count' => $count
];
$response = $this->get($uri, $query);
return $response;
}
public function addMembers($gid, array $add) {
return $this->updateMembers($gid, [ 'add' => $add ]);
}
public function removeMembers($gid, array $remove) {
return $this->updateMembers($gid, [ 'remove' => $remove ]);
}
public function updateMembers($gid, array $options) {
$uri = self::BASE_URI . $gid . '/members';
$body = $options;
$response = $this->post($uri, $body);
return $response;
}
public function members($gid) {
$uri = self::BASE_URI . $gid . '/members';
$response = $this->get($uri);
return $response;
}
}
<?php
namespace JMessage\IM;
use JMessage\IM;
class Message extends IM {
const BASE_URI = 'https://api.im.jpush.cn/v1/messages';
public function sendText($version, array $from, array $target, array $msg) {
$options = [
'version' => $version,
'target_type' => $target['type'],
'from_type' => $from['type'],
'msg_type' => 'text',
'target_id' => $target['id'],
'from_id' => $from['id'],
'msg_body' => [
'text' => $msg['text']
]
];
if (isset($from['name'])) {
$options['from_name'] = $from['name'];
}
if (isset($target['name'])) {
$options['target_name'] = $target['name'];
}
if (isset($msg['extras']) && is_array($msg['extras'])) {
$options['msg_body']['extras'] = $msg['extras'];
}
return $this->send($options);
}
public function sendImage($version, array $from, array $target, array $msg) {
$options = [
'version' => $version,
'target_type' => $target['type'],
'from_type' => $from['type'],
'msg_type' => 'image',
'target_id' => $target['id'],
'from_id' => $from['id'],
'msg_body' => [
'media_id' => $msg['mediaId'],
'media_crc32' => $msg['mediaCrc32'],
'width' => $msg['width'],
'height' => $msg['height'],
'format' => $msg['format'],
'fsize' => $msg['fsize']
]
];
if (isset($from['name'])) {
$options['from_name'] = $from['name'];
}
if (isset($target['name'])) {
$options['target_name'] = $target['name'];
}
if (isset($msg['extras']) && is_array($msg['extras'])) {
$options['msg_body']['extras'] = $msg['extras'];
}
return $this->send($options);
}
public function sendCustom($version, array $from, array $target, array $msg) {
$options = [
'version' => $version,
'target_type' => $target['type'],
'from_type' => $from['type'],
'msg_type' => 'custom',
'target_id' => $target['id'],
'from_id' => $from['id'],
'msg_body' => $msg
];
if (isset($from['name'])) {
$options['from_name'] = $from['name'];
}
if (isset($target['name'])) {
$options['target_name'] = $target['name'];
}
return $this->send($options);
}
public function send($options) {
$uri = self::BASE_URI;
$body = $options;
$response = $this->post($uri, $body);
return $response;
}
}
<?php
namespace JMessage\IM;
use JMessage\IM;
class Report extends IM {
const BASE_URL = 'https://report.im.jpush.cn/v1/';
public function getMessages($start, $count, $beginTime = null, $endTime = null) {
$uri = self::BASE_URL . 'messages';
return $this->report($uri, $start, $count, $beginTime, $endTime);
}
public function getUserMessages($username, $start, $count, $beginTime = null, $endTime = null) {
$uri = self::BASE_URL . '/users/' . $username . '/messages';
return $this->report($uri, $start, $count, $beginTime, $endTime);
}
private function report($uri, $start, $count, $beginTime = null, $endTime = null) {
$query = [
'start' => $start,
'count' => $count
];
if (!is_null($beginTime)) {
$query['begin_time'] = $beginTime;
}
if (!is_null($endTime)) {
$query['end_time'] = $endTime;
}
return $this->get($uri, $query);
}
}
<?php
namespace JMessage\IM;
use JMessage\IM;
class Resource extends IM {
const BASE_URI = 'https://api.im.jpush.cn/v1/resource';
public function download($mediaId) {
$uri = self::BASE_URI;
$query = [ 'mediaId' => $mediaId ];
$response = $this->get($uri, $query);
return $response;
}
public function upload($type, $path) {
$uri = self::BASE_URI . '?' . http_build_query(['type' => $type]);
$body = ['path' => $path];
$response = $this->getClient()->upload($uri, $body);
return $response;
}
}
<?php
namespace JMessage\IM;
use JMessage\IM;
class User extends IM {
const BASE_URI = 'https://api.im.jpush.cn/v1/users/';
public function register($username, $password) {
$body = [[
'username' => $username,
'password' => $password
]];
return $this->batchRegister($body);
}
public function batchRegister(array $users) {
$uri = self::BASE_URI;
$body = $users;
$response = $this->post($uri, $body);
return $response;
}
public function show($username) {
$uri = self::BASE_URI . $username;
$response = $this->get($uri);
return $response;
}
public function update($username, array $options) {
$uri = self::BASE_URI . $username;
$body = $options;
$response = $this->put($uri, $body);
return $response;
}
public function stat($username) {
$uri = self::BASE_URI . $username . '/userstat';
$response = $this->get($uri);
return $response;
}
public function updatePassword($username, $password) {
$uri = self::BASE_URI . $username . '/password';
$response = $this->put($uri, [ 'new_password' => $password ]);
return $response;
}
public function delete($username) {
$uri = self::BASE_URI . $username;
$response = $this->del($uri);
return $response;
}
public function listAll($start = 0, $count = 10) {
$uri = self::BASE_URI;
$query = [
'start' => $start,
'count' => $count
];
$response = $this->get($uri, $query);
return $response;
}
public function groups($username) {
$uri = self::BASE_URI . $username . '/groups';
$response = $this->get($uri);
return $response;
}
############## NoDisturb
public function addSingleNodisturb($touser, array $usernames) {
$single = [ 'add' => $usernames ];
return $this->nodisturb($touser, [ 'single' => $single ]);
}
public function removeSingleNodisturb($touser, array $usernames) {
$single = [ 'remove' => $usernames ];
return $this->nodisturb($touser, [ 'single' => $single ]);
}
public function addGroupNodisturb($touser, array $gids) {
$group = [ 'add' => $gids ];
return $this->nodisturb($touser, [ 'group' => $group ]);
}
public function removeGroupNodisturb($touser, array $gids) {
$group = [ 'remove' => $gids ];
return $this->nodisturb($touser, [ 'group' => $group ]);
}
// public function setGlobalNodisturb($touser, bool $opened) {
// return $this->nodisturb($touser, [ 'global' => (int)$opened ]);
// }
public function openGlobalNodisturb($touser) {
return $this->nodisturb($touser, [ 'global' => 1 ]);
}
public function closeGlobalNodisturb($touser) {
return $this->nodisturb($touser, [ 'global' => 0 ]);
}
public function nodisturb($touser, array $options) {
$uri = self::BASE_URI . $touser . '/nodisturb';
$body = $options;
$response = $this->post($uri, $body);
return $response;
}
}
<?php
namespace JMessage;
class JMessage {
private $appKey;
private $masterSecret;
private $options;
public function __construct($appKey, $masterSecret, array $options = []) {
$this->appKey = $appKey;
$this->masterSecret = $masterSecret;
$this->options = $options;
}
public function getAuth() {
return $this->appKey . ':' . $this->masterSecret;
}
}
# CHANGELOG
## 2.0.0
- changed the `__constructor` parameters. Now you inject an optional `Sirius\Validation\ValueValidator` instance instead of an `Sirius\Validation\ErrorMessage` instance
- changed dependency to Sirius\Validation~2.0
\ No newline at end of file
The MIT License (MIT)
Copyright (c) 2014 Adrian Miu
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
# Sirius\Upload
[![Source Code](http://img.shields.io/badge/source-siriusphp/upload-blue.svg?style=flat-square)](https://github.com/siriusphp/upload)
[![Latest Version](https://img.shields.io/packagist/v/siriusphp/upload.svg?style=flat-square)](https://github.com/siriusphp/upload/releases)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://github.com/siriusphp/upload/blob/master/LICENSE)
[![Build Status](https://img.shields.io/travis/siriusphp/upload/master.svg?style=flat-square)](https://travis-ci.org/siriusphp/upload)
[![PHP 7 ready](http://php7ready.timesplinter.ch/siriusphp/upload/master/badge.svg)](https://travis-ci.org/siriusphp/upload)
[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/siriusphp/upload.svg?style=flat-square)](https://scrutinizer-ci.com/g/siriusphp/upload/code-structure)
[![Quality Score](https://img.shields.io/scrutinizer/g/siriusphp/upload.svg?style=flat-square)](https://scrutinizer-ci.com/g/siriusphp/upload)
[![Total Downloads](https://img.shields.io/packagist/dt/siriusphp/upload.svg?style=flat-square)](https://packagist.org/packages/siriusphp/upload)
Framework agnostic upload handler library.
## Features
1. Validates files agains usual rules: extension, file size, image size (wdith, height, ratio). It uses [Sirius Validation](http://github.com/siriusphp/validation) for this purpose.
2. Moves valid uploaded files into containers. Containers are usually local folders but you can implement your own or use other filesystem abstractions like [Gaufrette](https://github.com/KnpLabs/Gaufrette) or [Flysystem](https://github.com/FrenkyNet/Flysystem).
## Elevator pitch
```php
use Sirius\Upload\Handler as UploadHandler;
$uploadHandler = new UploadHandler('/path/to/local_folder');
// validation rules
$uploadHandler->addRule('extension', ['allowed' => ['jpg', 'jpeg', 'png']], '{label} should be a valid image (jpg, jpeg, png)', 'Profile picture');
$uploadHandler->addRule('size', ['max' => '20M'], '{label} should have less than {max}', 'Profile picture');
$result = $uploadHandler->process($_FILES['picture']); // ex: subdirectory/my_headshot.png
if ($result->isValid()) {
// do something with the image like attaching it to a model etc
try {
$profile->picture = $result->name;
$profile->save();
$result->confirm(); // this will remove the .lock file
} catch (\Exception $e) {
// something wrong happened, we don't need the uploaded files anymore
$result->clear();
throw $e;
}
} else {
// image was not moved to the container, where are error messages
$messages = $result->getMessages();
}
```
##Links
- [documentation](http://www.sirius.ro/php/sirius/upload/)
- [changelog](CHANGELOG.md)
<?php
spl_autoload_register(function ($class) {
// what namespace prefix should be recognized?
$prefix = 'Sirius\Upload\\';
// does the requested class match the namespace prefix?
$prefix_len = strlen($prefix);
if (substr($class, 0, $prefix_len) !== $prefix) {
return;
}
// strip the prefix off the class
$class = substr($class, $prefix_len);
// a partial filename
$part = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
// directories where we can find classes
$dirs = array(
__DIR__ . DIRECTORY_SEPARATOR . 'src',
__DIR__ . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'src',
);
// go through the directories to find classes
foreach ($dirs as $dir) {
$file = $dir . DIRECTORY_SEPARATOR . $part;
if (is_readable($file)) {
require $file;
return;
}
}
});
\ No newline at end of file
{
"name": "siriusphp/upload",
"description": "Framework agnostic upload library",
"type": "library",
"license": "MIT",
"keywords": [
"form",
"upload",
"validation",
"file"
],
"authors": [
{
"name": "Adrian Miu",
"email": "adrian@adrianmiu.ro"
}
],
"require": {
"php": ">=5.3",
"siriusphp/validation": "~2.1"
},
"require-dev": {
"phpunit/phpunit": "~4.8"
},
"suggest": {
"league/flysystem": "To upload to different destinations, not just to the local file system",
"knplabs/gaufrette": "Alternative filesystem abstraction library for upload destinations"
},
"autoload": {
"psr-4": {
"Sirius\\Upload\\": "src/"
}
}
}
<?php
namespace Sirius\Upload\Container;
interface ContainerInterface
{
/**
* Check if the container is writable
*/
public function isWritable();
/**
* This will check if a file is in the container
*
* @param string $file
*/
public function has($file);
/**
* Saves the $content string as a file
*
* @param string $file
* @param string $content
*/
public function save($file, $content);
/**
* Delete the file from the container
*
* @param string $file
*/
public function delete($file);
/**
* Moves a temporary uploaded file to a destination in the container
*
* @param string $localFile local path
* @param string $destination
*/
public function moveUploadedFile($localFile, $destination);
}
<?php
namespace Sirius\Upload\Container;
class Local implements ContainerInterface
{
protected $baseDirectory;
public function __construct($baseDirectory)
{
$this->baseDirectory = $this->normalizePath($baseDirectory) . DIRECTORY_SEPARATOR;
$this->ensureDirectory($this->baseDirectory);
}
protected function normalizePath($path)
{
$path = dirname(rtrim($path, '\\/') . DIRECTORY_SEPARATOR . 'xxx');
return rtrim($path, DIRECTORY_SEPARATOR);
}
protected function ensureDirectory($directory)
{
if (!file_exists($directory)) {
mkdir($directory, 0755, true);
}
return is_dir($directory) && $this->isWritable();
}
/**
* Check if the container is writable
*/
public function isWritable()
{
return is_writable($this->baseDirectory);
}
/**
* This will check if a file is in the container
*
* @param string $file
* @return bool
*/
public function has($file)
{
return $file && file_exists($this->baseDirectory . $file);
}
/**
* Saves the $content string as a file
*
* @param string $file
* @param string $content
* @return bool
*/
public function save($file, $content)
{
$file = $this->normalizePath($file);
$dir = dirname($this->baseDirectory . $file);
if ($this->ensureDirectory($dir)) {
return (bool) file_put_contents($this->baseDirectory . $file, $content);
}
return false;
}
/**
* Delete the file from the container
*
* @param string $file
* @return bool
*/
public function delete($file)
{
$file = $this->normalizePath($file);
if (file_exists($this->baseDirectory . $file)) {
return unlink($this->baseDirectory . $file);
}
return true;
}
/**
* Moves a temporary uploaded file to a destination in the container
*
* @param string $localFile local path
* @param string $destination
* @return bool
*/
public function moveUploadedFile($localFile, $destination)
{
$dir = dirname($this->baseDirectory . $destination);
if (file_exists($localFile) && $this->ensureDirectory($dir)) {
/**
* we could use is_uploaded_file() and move_uploaded_file()
* but in case of ajax uploads that would fail
*/
if (is_readable($localFile)) {
// rename() would be good but this is better because $localFile may become 'unwritable'
$result = copy($localFile, $this->baseDirectory . $destination);
@unlink($localFile);
return $result;
}
}
return false;
}
}
<?php
namespace Sirius\Upload\Exception;
class InvalidContainerException extends \RuntimeException
{
}
<?php
namespace Sirius\Upload\Exception;
class InvalidResultException extends \RuntimeException
{
}
<?php
namespace Sirius\Upload;
use Sirius\Upload\Container\ContainerInterface;
use Sirius\Upload\Container\Local as LocalContainer;
use Sirius\Upload\Exception\InvalidContainerException;
use Sirius\Upload\Util\Arr;
use Sirius\Validation\ErrorMessage;
use Sirius\Validation\ValueValidator;
class Handler implements UploadHandlerInterface
{
// constants for constructor options
const OPTION_PREFIX = 'prefix';
const OPTION_OVERWRITE = 'overwrite';
const OPTION_AUTOCONFIRM = 'autoconfirm';
// constants for validation rules
const RULE_EXTENSION = 'extension';
const RULE_SIZE = 'size';
const RULE_IMAGE = 'image';
const RULE_IMAGE_HEIGHT = 'imageheight';
const RULE_IMAGE_WIDTH = 'imagewidth';
const RULE_IMAGE_RATIO = 'imageratio';
/**
* @var ContainerInterface
*/
protected $container;
/**
* Prefix to be added to the file.
* It can be a subfolder (if it ends with '/', a string to be used as prefix)
* or a callback that returns a string
*
* @var string|callback
*/
protected $prefix = '';
/**
* When uploading a file that has the same name as a file that is
* already in the container should it overwrite it or use another name
*
* @var boolean
*/
protected $overwrite = false;
/**
* Whether or not the uploaded files are auto confirmed
*
* @var boolean
*/
protected $autoconfirm = false;
/**
* @var \Sirius\Validation\ValueValidator
*/
protected $validator;
/**
* @var function|callback
*/
protected $sanitizerCallback;
/**
* @param $directoryOrContainer
* @param array $options
* @param ValueValidator $validator
* @throws InvalidContainerException
*/
public function __construct($directoryOrContainer, $options = array(), ValueValidator $validator = null)
{
$container = $directoryOrContainer;
if (is_string($directoryOrContainer)) {
$container = new LocalContainer($directoryOrContainer);
}
if (!$container instanceof ContainerInterface) {
throw new InvalidContainerException('Destination container for uploaded files is not valid');
}
$this->container = $container;
// create the validator
if (!$validator) {
$validator = new ValueValidator();
}
$this->validator = $validator;
// set options
$availableOptions = array(
static::OPTION_PREFIX => 'setPrefix',
static::OPTION_OVERWRITE => 'setOverwrite',
static::OPTION_AUTOCONFIRM => 'setAutoconfirm'
);
foreach ($availableOptions as $key => $method) {
if (isset($options[$key])) {
$this->{$method}($options[$key]);
}
}
}
/**
* Enable/disable upload overwrite
*
* @param bool $overwrite
* @return \Sirius\Upload\Handler
*/
public function setOverwrite($overwrite)
{
$this->overwrite = (bool) $overwrite;
return $this;
}
/**
* File prefix for the upload. Can be
* - a folder (if it ends with /)
* - a string to be used as prefix
* - a function that returns a string
*
* @param string|callable $prefix
* @return \Sirius\Upload\Handler
*/
public function setPrefix($prefix)
{
$this->prefix = $prefix;
return $this;
}
/**
* Enable/disable upload autoconfirmation
* Autoconfirmation does not require calling `confirm()`
*
* @param boolean $autoconfirm
* @return \Sirius\Upload\Handler
*/
public function setAutoconfirm($autoconfirm)
{
$this->autoconfirm = (bool) $autoconfirm;
return $this;
}
/**
* Set the sanitizer function for cleaning up the file names
*
* @param callable $callback
* @throws \InvalidArgumentException
* @return \Sirius\Upload\Handler
*/
function setSanitizerCallback($callback)
{
if (!is_callable($callback)) {
throw new \InvalidArgumentException('The $callback parameter is not a valid callable entity');
}
$this->sanitizerCallback = $callback;
return $this;
}
/**
* Add validation rule (extension|size|width|height|ratio)
*
* @param string $name
* @param mixed $options
* @param string $errorMessageTemplate
* @param string $label
* @return \Sirius\Upload\Handler
*/
public function addRule($name, $options = null, $errorMessageTemplate = null, $label = null)
{
$predefinedRules = array(
static::RULE_EXTENSION,
static::RULE_IMAGE,
static::RULE_SIZE,
static::RULE_IMAGE_WIDTH,
static::RULE_IMAGE_HEIGHT,
static::RULE_IMAGE_RATIO
);
// convert to a name that is known by the default RuleFactory
if (in_array($name, $predefinedRules)) {
$name = 'upload' . $name;
}
$this->validator->add($name, $options, $errorMessageTemplate, $label);
return $this;
}
/**
* Processes a file upload and returns an upload result file/collection
*
* @param array $files
* @return Result\Collection|Result\File
*/
public function process($files = array())
{
$files = Arr::normalizeFiles($files);
foreach ($files as $k => $file) {
$files[$k] = $this->processSingleFile($file);
}
if (count($files) == 1) {
return new Result\File(array_pop($files), $this->container);
}
return new Result\Collection($files, $this->container);
}
/**
* Processes a single uploaded file
* - sanitize the name
* - validates the file
* - if valid, moves the file to the container
*
* @param array $file
* @return array
*/
protected function processSingleFile(array $file)
{
// store it for future reference
$file['original_name'] = $file['name'];
// sanitize the file name
$file['name'] = $this->sanitizeFileName($file['name']);
$file = $this->validateFile($file);
// if there are messages the file is not valid
if (isset($file['messages']) && $file['messages']) {
return $file;
}
// add the prefix
$prefix = '';
if (is_callable($this->prefix)) {
$prefix = (string) call_user_func($this->prefix, $file['name']);
} elseif (is_string($this->prefix)) {
$prefix = (string) $this->prefix;
}
// if overwrite is not allowed, check if the file is already in the container
if (!$this->overwrite) {
if ($this->container->has($prefix . $file['name'])) {
// add the timestamp to ensure the file is unique
// method is not bulletproof but it's pretty safe
$file['name'] = time() . '_' . $file['name'];
}
}
// attempt to move the uploaded file into the container
if (!$this->container->moveUploadedFile($file['tmp_name'], $prefix . $file['name'])) {
$file['name'] = false;
return $file;
}
$file['name'] = $prefix . $file['name'];
// create the lock file if autoconfirm is disabled
if (!$this->autoconfirm) {
$this->container->save($file['name'] . '.lock', time());
}
return $file;
}
/**
* Validates a file according to the rules configured on the handler
*
* @param $file
* @return mixed
*/
protected function validateFile($file)
{
if (!$this->validator->validate($file)) {
$file['messages'] = $this->validator->getMessages();
}
return $file;
}
/**
* Sanitize the name of the uploaded file by stripping away bad characters
* and replacing "invalid" characters with underscore _
*
* @param string $name
* @return string
*/
protected function sanitizeFileName($name)
{
if ($this->sanitizerCallback) {
return call_user_func($this->sanitizerCallback, $name);
}
return preg_replace('/[^A-Za-z0-9\.]+/', '_', $name);
}
}
<?php
namespace Sirius\Upload;
use Sirius\Upload\Result\Collection;
use Sirius\Upload\Util\Arr;
class HandlerAggregate implements \IteratorAggregate
{
protected $handlers = array();
/**
* Adds a handler on the aggregate
*
* @param string $selector
* @param Handler $handler
* @return $this
*/
public function addHandler($selector, Handler $handler)
{
$this->handlers[$selector] = $handler;
return $this;
}
/**
* Processes
* @param $files
* @return Collection
*/
public function process($files)
{
$result = new Collection();
foreach ($this->handlers as $selector => $handler) {
/* @var $handler Handler */
$selectedFiles = Arr::getBySelector($files, $selector);
if (!$selectedFiles || !is_array($selectedFiles) || empty($selectedFiles)) {
continue;
}
foreach ($selectedFiles as $path => $file) {
if (is_array($file)) {
$result[$path] = $handler->process($file);
}
}
}
return $result;
}
/**
* (PHP 5 &gt;= 5.0.0)<br/>
* Retrieve an external iterator
*
* @link http://php.net/manual/en/iteratoraggregate.getiterator.php
* @return \Traversable An instance of an object implementing <b>Iterator</b> or
* <b>Traversable</b>
*/
public function getIterator()
{
return $this->handlers;
}
}
<?php
namespace Sirius\Upload\Result;
use Sirius\Upload\Container\ContainerInterface;
class Collection extends \ArrayIterator
{
public function __construct($files = array(), ContainerInterface $container = null)
{
$filesArray = array();
if (is_array($files) && !empty($files)) {
foreach ($files as $key => $file) {
$filesArray[$key] = new File($file, $container);
}
}
parent::__construct($filesArray);
}
public function clear()
{
foreach ($this as $file) {
/* @var $file \Sirius\Upload\Result\File */
$file->clear();
}
}
public function confirm()
{
foreach ($this as $file) {
/* @var $file \Sirius\Upload\Result\File */
$file->confirm();
}
}
public function isValid()
{
foreach ($this->getMessages() as $messages) {
if ($messages) {
return false;
}
}
return true;
}
public function getMessages()
{
$messages = array();
foreach ($this as $key => $file) {
/* @var $file \Sirius\Upload\Result\File */
$messages[$key] = $file->getMessages();
}
return $messages;
}
}
<?php
namespace Sirius\Upload\Result;
use Sirius\Upload\Container\ContainerInterface;
class File
{
/**
* Array containing the details of the uploaded file:
* - name (uploaded name)
* - original name
* - tmp_name
* etc
*
* @var array
*/
protected $file;
/**
* The container to which this file belongs to
* @var \Sirius\Upload\Container\ContainerInterface
*/
protected $container;
/**
* @param $file
* @param ContainerInterface $container
*/
public function __construct($file, ContainerInterface $container)
{
$this->file = $file;
$this->container = $container;
}
/**
* Returns if the uploaded file is valid
*
* @return bool
*/
public function isValid()
{
return $this->file['name'] && count($this->getMessages()) === 0;
}
/**
* Returns the validation error messages
*
* @return array
*/
public function getMessages()
{
if (isset($this->file['messages'])) {
return $this->file['messages'];
} else {
return array();
}
}
/**
* The file that was saved during process() and has a .lock file attached
* will be cleared, in case the form processing fails
*/
public function clear()
{
$this->container->delete($this->name);
$this->container->delete($this->name . '.lock');
$this->file['name'] = null;
}
/**
* Remove the .lock file attached to the file that was saved during process()
* This should happen if the form fails validation/processing
*/
public function confirm()
{
$this->container->delete($this->name . '.lock');
}
/**
* File attribute getter
*
* @param $name
* @return mixed
*/
public function __get($name)
{
if (isset($this->file[$name])) {
return $this->file[$name];
}
return null;
}
}
<?php
namespace Sirius\Upload;
interface UploadHandlerInterface
{
/**
* This function will process the files received from $_FILES,
* validate them and save them into the container.
*
* Along with the file saved into the container a .lock file should
* be added by the container save() method so, in case the form is
* not validated, the uploaded file will be removed.
*
* @param array $files
*/
public function process($files = array());
}
<?php
namespace Sirius\Upload\Util;
class Arr extends \Sirius\Validation\Util\Arr
{
public static function remapFilesArray(array $files)
{
$result = array();
foreach ($files['name'] as $k => $v) {
$result[$k] = array(
'name' => $files['name'][$k],
'type' => @$files['type'][$k],
'size' => @$files['size'][$k],
'error' => @$files['error'][$k],
'tmp_name' => $files['tmp_name'][$k]
);
}
return $result;
}
/**
* Fixes the $_FILES array problem and ensures the result is an array of files
*
* PHP's $_FILES variable is not properly formated for iteration when
* multiple files are uploaded under the same name
* @see http://www.php.net/manual/en/features.file-upload.php
*
* @param array $files
* @return array
*/
public static function normalizeFiles(array $files)
{
// The caller passed $_FILES['some_field_name']
if (isset($files['name'])) {
// we have a single file
if(!is_array($files['name'])) {
return array($files);
}
// we have list of files, which PHP messes up
else {
return Arr::remapFilesArray($files);
}
}
// The caller passed $_FILES
else {
$keys = array_keys($files);
if (isset($keys[0]) && isset($files[$keys[0]]['name'])) {
if (!is_array($files[$keys[0]]['name'])) {
// $files is in the correct format already, even in the
// case it contains a single element.
return $files;
}
// we have list of files, which PHP messes up
else {
return Arr::remapFilesArray($files[$keys[0]]);
}
}
}
// if we got here, the $file argument is wrong
return array();
}
}
; This file is for unifying the coding style for different editors and IDEs.
; More information at http://editorconfig.org
root = true
[*]
charset = utf-8
indent_size = 4
indent_style = space
end_of_line = lf
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
trim_trailing_whitespace = false
#### 2.2.0
- added `Upload\Required` rule
- fixed upload validators when the upload was not successful
#### 2.0.0
- added the `data_selector:label` feature
- implemented default rule messages in the `RuleFactory` class. This way, if you have a custom error message for the `required` fields, you don't have to provide it to all the required fields, just set it up once in the `RuleFactory`
- implemented a way to allow validation rule options to be passed as CSV (eg: '100,200' instead of 'min=200&max=200')
#### 1.2.4
- added PHP7 to Travis CI
- fixed bug with validating non-required elements (issue #17)
#### 1.2.2
- fixed bug with the 'between' validator (pull request #16)
- added support for PHP 5.3 (tests fail but due to the short array syntax, not the inherent code in the library)
- improved documentation on how to use complex validators (ie: that have dependencies)
#### 1.2.1
- fixed bug with the required rule not working properly on empty strings
#### 1.2.0
- improved the code base on Scrutinizer CI suggestions
- removed the ValidatableTrait trait
#### 1.1.0
- Added HHVM to Travis CI
- Renamed Validator\* classes into Rule\* classes (breaking change if you used custom rule classes)
- Renamed ValidatorFactory to RuleFactory (breaking change)
The MIT License (MIT)
Copyright (c) 2013 Adrian Miu
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software is furnished to do so,
subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
<?php
spl_autoload_register(function ($class) {
// what namespace prefix should be recognized?
$prefix = 'Sirius\Validation\\';
// does the requested class match the namespace prefix?
$prefix_len = strlen($prefix);
if (substr($class, 0, $prefix_len) !== $prefix) {
return;
}
// strip the prefix off the class
$class = substr($class, $prefix_len);
// a partial filename
$part = str_replace('\\', DIRECTORY_SEPARATOR, $class) . '.php';
// directories where we can find classes
$dirs = array(
__DIR__ . DIRECTORY_SEPARATOR . 'src',
__DIR__ . DIRECTORY_SEPARATOR . 'tests' . DIRECTORY_SEPARATOR . 'src',
);
// go through the directories to find classes
foreach ($dirs as $dir) {
$file = $dir . DIRECTORY_SEPARATOR . $part;
if (is_readable($file)) {
require $file;
return;
}
}
});
{
"name": "siriusphp/validation",
"description": "Data validation library. Validate arrays, array objects, domain models etc using a simple API. Easily add your own validators on top of the already dozens built-in validation rules",
"type": "library",
"license": "MIT",
"keywords": [
"form",
"validation",
"sanitization",
"security",
"modeling"
],
"authors": [
{
"name": "Adrian Miu",
"email": "adrian@adrianmiu.ro"
}
],
"require": {
"php": ">=5.3"
},
"require-dev": {
"phpunit/phpunit": "^3.7"
},
"autoload": {
"psr-4": {
"Sirius\\Validation\\": "src/"
}
},
"scripts": {
"phpcs": [
"php phpcs.phar --standard=PSR2 ./src"
],
"phpmd": [
"php phpmd.phar ./src xml phpmd.xml"
],
"phpcbf": [
"php phpcbf.phar ./src --standard=PSR2 -w"
],
"phpcsfix": [
"php php-cs-fixer.phar fix ./src --rules=@PSR2"
]
}
}
<?xml version="1.0"?>
<ruleset name="Sirius PMD ruleset" xmlns="http://pmd.sf.net/ruleset/1.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://pmd.sf.net/ruleset/1.0.0 http://pmd.sf.net/ruleset_xml_schema.xsd"
xsi:noNamespaceSchemaLocation=" http://pmd.sf.net/ruleset_xml_schema.xsd">
<description>Sirius PMD ruleset</description>
<rule ref="rulesets/codesize.xml">
<exclude name="CyclomaticComplexity"/>
<exclude name="ExcessiveMethodLength"/>
<exclude name="NPathComplexity"/>
<exclude name="TooManyMethods"/>
<exclude name="ExcessiveClassComplexity"/>
</rule>
<rule ref="rulesets/design.xml"/>
<rule ref="rulesets/naming.xml/LongVariable">
<properties>
<property name="maximum" value="25"/>
</properties>
</rule>
<rule ref="rulesets/naming.xml">
<exclude name="LongVariable"/>
<exclude name="ShortVariable"/>
</rule>
<rule ref="rulesets/unusedcode.xml">
<exclude name="UnusedFormalParameter"/>
</rule>
</ruleset>
\ No newline at end of file
#Sirius Validation
[![Source Code](http://img.shields.io/badge/source-siriusphp/validation-blue.svg?style=flat-square)](https://github.com/siriusphp/validation)
[![Latest Version](https://img.shields.io/packagist/v/siriusphp/validation.svg?style=flat-square)](https://github.com/siriusphp/validation/releases)
[![Software License](https://img.shields.io/badge/license-MIT-brightgreen.svg?style=flat-square)](https://github.com/siriusphp/validation/blob/master/LICENSE)
[![Build Status](https://img.shields.io/travis/siriusphp/validation/master.svg?style=flat-square)](https://travis-ci.org/siriusphp/validation)
[![PHP 7 ready](http://php7ready.timesplinter.ch/siriusphp/validation/master/badge.svg)](https://travis-ci.org/siriusphp/validation)
[![Coverage Status](https://img.shields.io/scrutinizer/coverage/g/siriusphp/validation.svg?style=flat-square)](https://scrutinizer-ci.com/g/siriusphp/validation/code-structure)
[![Quality Score](https://img.shields.io/scrutinizer/g/siriusphp/validation.svg?style=flat-square)](https://scrutinizer-ci.com/g/siriusphp/validation)
[![Total Downloads](https://img.shields.io/packagist/dt/siriusphp/validation.svg?style=flat-square)](https://packagist.org/packages/siriusphp/validation)
Sirius Validation is a library for data validation. It offers:
1. [validator object](docs/validator.md)
2. [45 build-in validation rules](docs/validation_rules.md). There are validators for strings, array, numbers, emails, URLs, files and uploads
3. [validation helper](docs/helper.md) to simplify the validation of single values
Out-of-the-box, the library can handle `array`s, `ArrayObject`s and objects that have implemented the `toArray` method.
In order to validate other data containers you must create a [`DataWrapper`](https://github.com/siriusphp/validation/blob/master/src/Validation/DataWrapper/WrapperInterface.php) so that the validator be able to extract data from your object.
##Elevator pitch
```php
$validator = new \Sirius\Validation\Validator;
// add a validation rule
$validator->add('title', 'required');
// add a rule that has a list of options
$validator->add('title', 'length', array('min' => 10, 'max' => 100));
// or use JSON
$validator->add('title', 'length', '{"min": 10, "max": 100}');
// or a URL query string
$validator->add('title', 'length', 'min=10&max=100');
// or, if you know that the validator can CORECTLY parse (ie: understand) the options string
$validator->add('title', 'length', '10,100');
// add a rule with a custom error message
$validator->add('title', 'maxlength', 'max=100', 'Article title must have less than {max} characters');
// add a rule with a custom message and a label (very handy with forms)
$validator->add('title:Title', 'maxlength', 'max=100', '{label} must have less than {max} characters');
// add all of rule's configuration in a string (you'll see later why it's handy')
$validator->add('title:Title', 'maxlength(max=255)({label} must have less than {max} characters)');
// add multiple rules at once (separate using [space][pipe][space])
$validator->add('title:Title', 'required | maxlength(255) | minlength(min=10)');
// add all your rules at once
$validator->add(array(
'title:Title' => 'required | maxlength(100)({label} must have less than {max} characters)',
'content:Content' => 'required',
'source:Source' => 'website'
));
// add nested rules
$validator->add('recipients[*]:Recipients', 'email'); //all recipients must be valid email addresses
$validator->add('shipping_address[city]:City', 'MyApp\Validator\City'); // uses a custom validator to validate the shipping city
```
##Links
- [documentation](http://sirius.ro/php/sirius/validation/)
- [changelog](CHANGELOG.md)
##Known issues
In PHP 5.3 there is some problem with the SplObject storage that prevents the library to remove validation rules.
This means that in PHP 5.3, you cannot remove a validation rule from a `Validator` or `ValueValidator` object
<?php
namespace Sirius\Validation\DataWrapper;
use Sirius\Validation\Util\Arr;
use Sirius\Validation\DataWrapper\WrapperInterface;
class ArrayWrapper implements WrapperInterface
{
/**
* @var array
*/
protected $data = array();
/**
* @param array|\ArrayObject|object $data
*
* @throws \InvalidArgumentException
*/
public function __construct($data = array())
{
if (is_object($data)) {
if ($data instanceof \ArrayObject) {
$data = $data->getArrayCopy();
} elseif (method_exists($data, 'toArray')) {
$data = $data->toArray();
}
}
if (! is_array($data)) {
throw new \InvalidArgumentException('Data passed to validator is not an array or an ArrayObject');
}
$this->data = $data;
}
public function getItemValue($item)
{
return Arr::getByPath($this->data, $item);
}
public function getItemsBySelector($selector)
{
return Arr::getBySelector($this->data, $selector);
}
}
<?php
namespace Sirius\Validation\DataWrapper;
interface WrapperInterface
{
/**
* Get value from the data container using the path
*
* @param $item
*
* @return mixed
*/
public function getItemValue($item);
/**
* Get items by selector
*
* @param $selector
*
* @return array
*/
public function getItemsBySelector($selector);
}
<?php
namespace Sirius\Validation;
class ErrorMessage
{
protected $template = 'Invalid';
protected $variables = array();
public function __construct($template = '', $variables = array())
{
$this->setTemplate($template)
->setVariables($variables);
}
public function setTemplate($template)
{
$template = trim((string) $template);
if ($template) {
$this->template = (string) $template;
}
return $this;
}
public function getTemplate()
{
return $this->template;
}
public function setVariables($variables = array())
{
foreach ($variables as $k => $v) {
$this->variables[$k] = $v;
}
return $this;
}
public function getVariables()
{
return $this->variables;
}
public function __toString()
{
$result = $this->template;
foreach ($this->variables as $k => $v) {
if (strpos($result, "{{$k}}") !== false) {
$result = str_replace("{{$k}}", $v, $result);
}
}
return $result;
}
}
<?php
namespace Sirius\Validation;
use Sirius\Validation\Util\Arr;
class Helper
{
protected static $methods = array();
public static function addMethod($ruleName, $callback)
{
if (is_callable($callback)) {
self::$methods[$ruleName] = $callback;
return true;
}
return false;
}
public static function methodExists($name)
{
return method_exists(__CLASS__, $name) || array_key_exists($name, self::$methods);
}
public static function __callStatic($name, $arguments)
{
if (array_key_exists($name, self::$methods)) {
return call_user_func_array(self::$methods[$name], $arguments);
}
throw new \InvalidArgumentException(sprintf('Validation method "%s" does not exist', $name));
}
public static function callback($value, $callback, $context = array())
{
$validator = new Rule\Callback();
$validator->setOption('callback', $callback);
$validator->setContext($context);
return $validator->validate($value);
}
public static function required($value)
{
return $value !== null && trim($value) !== '';
}
public static function truthy($value)
{
return (bool) $value;
}
public static function falsy($value)
{
return ! static::truthy($value);
}
public static function number($value)
{
return $value == '0' || is_numeric($value);
}
public static function integer($value)
{
return $value == '0' || (int) $value == $value;
}
public static function lessThan($value, $max)
{
$validator = new Rule\LessThan(
array(
'max' => $max
)
);
return $validator->validate($value);
}
public static function greaterThan($value, $min)
{
$validator = new Rule\GreaterThan(
array(
'min' => $min
)
);
return $validator->validate($value);
}
public static function between($value, $min, $max)
{
$validator = new Rule\Between(
array(
'min' => $min,
'max' => $max
)
);
return $validator->validate($value);
}
public static function exactly($value, $otherValue)
{
return $value == $otherValue;
}
public static function not($value, $otherValue)
{
return ! self::exactly($value, $otherValue);
}
public static function alpha($value)
{
$validator = new Rule\Alpha();
return $validator->validate($value);
}
public static function alphanumeric($value)
{
$validator = new Rule\AlphaNumeric();
return $validator->validate($value);
}
public static function alphanumhyphen($value)
{
$validator = new Rule\AlphaNumHyphen();
return $validator->validate($value);
}
public static function minLength($value, $min)
{
$validator = new Rule\MinLength(
array(
'min' => $min
)
);
return $validator->validate($value);
}
public static function maxLength($value, $max)
{
$validator = new Rule\MaxLength(
array(
'max' => $max
)
);
return $validator->validate($value);
}
public static function length($value, $min, $max)
{
$validator = new Rule\Length(
array(
'min' => $min,
'max' => $max
)
);
return $validator->validate($value);
}
public static function setMinSize($value, $min)
{
$validator = new Rule\ArrayMinLength(
array(
'min' => $min
)
);
return $validator->validate($value);
}
public static function setMaxSize($value, $max)
{
$validator = new Rule\ArrayMaxLength(
array(
'max' => $max
)
);
return $validator->validate($value);
}
public static function setSize($value, $min, $max)
{
$validator = new Rule\ArrayLength(
array(
'min' => $min,
'max' => $max
)
);
return $validator->validate($value);
}
public static function inList($value, $values)
{
$validator = new Rule\InList(
array(
'list' => $values
)
);
return $validator->validate($value);
}
public static function notInList($value, $values)
{
$validator = new Rule\NotInList(
array(
'list' => $values
)
);
return $validator->validate($value);
}
public static function regex($value, $pattern)
{
$validator = new Rule\Regex(
array(
'pattern' => $pattern
)
);
return $validator->validate($value);
}
public static function notRegex($value, $pattern)
{
$validator = new Rule\NotRegex(
array(
'pattern' => $pattern
)
);
return $validator->validate($value);
}
public static function equalTo($value, $otherElementOrValue, $context = null)
{
if (func_num_args() == 2) {
return $value == $otherElementOrValue;
}
return $value == Arr::getByPath($context, $otherElementOrValue);
}
public static function date($value, $format = 'Y-m-d')
{
$validator = new Rule\Date(
array(
'format' => $format
)
);
return $validator->validate($value);
}
public static function dateTime($value, $format = 'Y-m-d H:i:s')
{
$validator = new Rule\DateTime(
array(
'format' => $format
)
);
return $validator->validate($value);
}
public static function time($value, $format = 'H:i:s')
{
$validator = new Rule\Time(
array(
'format' => $format
)
);
return $validator->validate($value);
}
public static function website($value)
{
$validator = new Rule\Website();
return $validator->validate($value);
}
public static function url($value)
{
$validator = new Rule\Url();
return $validator->validate($value);
}
/**
* Test if a variable is a valid IP address
*
* @param string $value
*
* @return bool
*/
public static function ipAddress($value)
{
$validator = new Rule\IpAddress();
return $validator->validate($value);
}
public static function email($value)
{
$validator = new Rule\Email();
return $validator->validate($value);
}
/**
* Test if a variable is a full name
* Criterias: at least 6 characters, 2 words
*
* @param mixed $value
*
* @return bool
*/
public static function fullName($value)
{
$validator = new Rule\FullName();
return $validator->validate($value);
}
/**
* Test if the domain of an email address is available
*
* @param string $value
*
* @return bool
*/
public static function emailDomain($value)
{
$validator = new Rule\EmailDomain();
return $validator->validate($value);
}
}
<?php
namespace Sirius\Validation\Rule;
abstract class AbstractStringRule extends AbstractRule
{
protected function getStringLength($str)
{
if (function_exists('mb_strlen')) {
return mb_strlen(
$str,
(isset($this->options['encoding']) && $this->options['encoding']) ?
$this->options['encoding'] : mb_internal_encoding()
);
}
return strlen($str);
}
}
<?php
namespace Sirius\Validation\Rule;
class Alpha extends AbstractRule
{
const MESSAGE = 'This input can contain only letters';
const LABELED_MESSAGE = '{label} can contain only letters';
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
$this->success = (bool) ctype_alpha((string) str_replace(' ', '', $value));
return $this->success;
}
}
<?php
namespace Sirius\Validation\Rule;
class AlphaNumHyphen extends AbstractRule
{
const MESSAGE = 'This input must contain only letters, digits, spaces, hyphens and underscores';
const LABELED_MESSAGE = '{label} must contain only letters, digits, spaces, hyphens and underscores';
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
$this->success = (bool) ctype_alnum(
(string) str_replace(
array(
' ',
'_',
'-'
),
'',
$value
)
);
return $this->success;
}
}
<?php
namespace Sirius\Validation\Rule;
class AlphaNumeric extends AbstractRule
{
const MESSAGE = 'This input must contain only letters and digits';
const LABELED_MESSAGE = '{label} must contain only letters and digits';
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
$this->success = (bool) ctype_alnum((string) str_replace(' ', '', $value));
return $this->success;
}
}
<?php
namespace Sirius\Validation\Rule;
class ArrayLength extends AbstractRule
{
const OPTION_MIN = 'min';
const OPTION_MAX = 'max';
const MESSAGE = 'This input should contain between {min} and {max} items';
const LABELED_MESSAGE = '{label} should contain between {min} and {max} items';
protected $options = array();
protected $optionsIndexMap = array(
0 => self::OPTION_MIN,
1 => self::OPTION_MAX
);
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
$maxValidator = new ArrayMaxLength();
if (isset($this->options['max'])) {
$maxValidator->setOption('max', $this->options['max']);
}
$minValidator = new ArrayMinLength();
if (isset($this->options['min'])) {
$minValidator->setOption('min', $this->options['min']);
}
$this->success = $minValidator->validate($value, $valueIdentifier) && $maxValidator->validate(
$value,
$valueIdentifier
);
return $this->success;
}
}
<?php
namespace Sirius\Validation\Rule;
class ArrayMaxLength extends AbstractRule
{
const OPTION_MAX = 'max';
const MESSAGE = 'This input should contain less than {min} items';
const LABELED_MESSAGE = '{label} should contain less than {min} items';
protected $options = array();
protected $optionsIndexMap = array(
self::OPTION_MAX
);
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
if (! isset($this->options['max'])) {
$this->success = true;
} else {
$this->success = is_array($value) && count($value) <= $this->options['max'];
}
return $this->success;
}
}
<?php
namespace Sirius\Validation\Rule;
class ArrayMinLength extends AbstractRule
{
const OPTION_MIN = 'min';
const MESSAGE = 'This input should contain at least {min} items';
const LABELED_MESSAGE = '{label} should contain at least {min} items';
protected $options = array();
protected $optionsIndexMap = array(
0 => self::OPTION_MIN
);
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
if (! isset($this->options['min'])) {
$this->success = true;
} else {
$this->success = is_array($value) && count($value) >= $this->options['min'];
}
return $this->success;
}
}
<?php
namespace Sirius\Validation\Rule;
class Between extends AbstractRule
{
const OPTION_MIN = 'min';
const OPTION_MAX = 'max';
const MESSAGE = 'This input must be between {min} and {max}';
const LABELED_MESSAGE = '{label} must be between {min} and {max}';
protected $options = array();
protected $optionsIndexMap = array(
0 => self::OPTION_MIN,
1 => self::OPTION_MAX
);
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
$minValidator = new LessThan();
if (isset($this->options['max'])) {
$minValidator->setOption('max', $this->options['max']);
}
$maxValidator = new GreaterThan();
if (isset($this->options['min'])) {
$maxValidator->setOption('min', $this->options['min']);
}
$this->success = $minValidator->validate($value, $valueIdentifier) && $maxValidator->validate(
$value,
$valueIdentifier
);
return $this->success;
}
}
<?php
namespace Sirius\Validation\Rule;
class Callback extends AbstractRule
{
const OPTION_CALLBACK = 'callback';
const OPTION_ARGUMENTS = 'arguments';
const MESSAGE = 'This input does not meet the validation criteria';
const LABELED_MESSAGE = '{label} does not meet the validation criteria';
public function getUniqueId()
{
$uniqueId = get_called_class();
// the callback is a function name (eg: is_int) or a static class method (eg: MyClass::method)
if (is_string($this->options['callback'])) {
$uniqueId .= '|' . $this->options['callback'];
} elseif (is_array($this->options['callback'])) {
// the callback is an array that points to a static class method (eg: array('MyClass', 'method'))
if (is_string($this->options['callback'][0])) {
$uniqueId .= '|' . implode('::', $this->options['callback']);
} elseif (is_object($this->options['callback'][0])) {
$uniqueId .= '|' . spl_object_hash(
$this->options['callback'][0]
) . '->' . $this->options['callback'][1];
}
} elseif (is_object($this->options['callback']) && $this->options['callback'] instanceof \Closure) {
$uniqueId .= '|' . spl_object_hash($this->options['callback']);
}
if (isset($this->options['arguments'])) {
$args = (array) $this->options['arguments'];
ksort($args);
$uniqueId .= '|' . json_encode($args);
}
return $uniqueId;
}
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
if (! isset($this->options['callback']) || ! is_callable($this->options['callback'])) {
$this->success = true;
} else {
$args = (isset($this->options['arguments'])) ? (array) $this->options['arguments'] : array();
array_unshift($args, $value);
array_push($args, $valueIdentifier, $this->context);
$this->success = (bool) call_user_func_array($this->options['callback'], $args);
}
return $this->success;
}
}
<?php
namespace Sirius\Validation\Rule;
class Date extends AbstractRule
{
const OPTION_FORMAT = 'format';
const MESSAGE = 'This input must be a date having the format {format}';
const LABELED_MESSAGE = '{label} must be a date having the format {format}';
protected $options = array(
'format' => 'Y-m-d'
);
protected $optionsIndexMap = array(
0 => self::OPTION_FORMAT
);
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
$this->success = $value == date(
$this->options['format'],
$this->getTimestampFromFormatedString($value, $this->options['format'])
);
return $this->success;
}
protected function getTimestampFromFormatedString($string, $format)
{
$result = date_parse_from_format($format, $string);
return mktime(
(int) $result['hour'],
(int) $result['minute'],
(int) $result['second'],
(int) $result['month'],
(int) $result['day'],
(int) $result['year']
);
}
}
<?php
namespace Sirius\Validation\Rule;
class DateTime extends Date
{
const MESSAGE = 'This input must be a date having the format {format}';
const LABELED_MESSAGE = '{label} must be a date having the format {format}';
protected $options = array(
'format' => 'Y-m-d H:i:s'
);
}
<?php
namespace Sirius\Validation\Rule;
class Email extends AbstractRule
{
const MESSAGE = 'This input must be a valid email address';
const LABELED_MESSAGE = '{label} must be a valid email address';
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
$this->success = (filter_var((string) $value, FILTER_VALIDATE_EMAIL) !== false);
return $this->success;
}
}
<?php
namespace Sirius\Validation\Rule;
class EmailDomain extends AbstractRule
{
const MESSAGE = 'This the email address does not belong to a valid domain';
const LABELED_MESSAGE = '{label} does not belong to a valid domain';
public function validate($value, $valueIdentifier = null)
{
$value = (string) $value;
$this->value = $value;
// Check if the email domain has a valid MX record
$this->success = (bool) checkdnsrr(preg_replace('/^[^@]+@/', '', $value), 'MX');
return $this->success;
}
}
<?php
namespace Sirius\Validation\Rule;
class Equal extends AbstractRule
{
const OPTION_VALUE = 'value';
const MESSAGE = 'This input is not equal to {value}';
const LABELED_MESSAGE = '{label} is not equal to {value}';
protected $optionsIndexMap = array(
0 => self::OPTION_VALUE
);
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
if (isset($this->options[self::OPTION_VALUE])) {
$this->success = ($value == $this->options[self::OPTION_VALUE]);
} else {
$this->success = true;
}
return $this->success;
}
}
<?php
namespace Sirius\Validation\Rule\File;
use Sirius\Validation\Rule\AbstractRule;
class Extension extends AbstractRule
{
const OPTION_ALLOWED_EXTENSIONS = 'allowed';
const MESSAGE = 'The file does not have an acceptable extension ({file_extensions})';
const LABELED_MESSAGE = '{label} does not have an acceptable extension ({file_extensions})';
protected $options = array(
self::OPTION_ALLOWED_EXTENSIONS => array()
);
public function setOption($name, $value)
{
if ($name == self::OPTION_ALLOWED_EXTENSIONS) {
if (is_string($value)) {
$value = explode(',', $value);
}
$value = array_map('trim', $value);
$value = array_map('strtolower', $value);
}
return parent::setOption($name, $value);
}
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
if (! file_exists($value)) {
$this->success = false;
} else {
$extension = strtolower(substr($value, strrpos($value, '.') + 1, 10));
$this->success = is_array($this->options[self::OPTION_ALLOWED_EXTENSIONS]) && in_array(
$extension,
$this->options[self::OPTION_ALLOWED_EXTENSIONS]
);
}
return $this->success;
}
public function getPotentialMessage()
{
$message = parent::getPotentialMessage();
$fileExtensions = array_map('strtoupper', $this->options[self::OPTION_ALLOWED_EXTENSIONS]);
$message->setVariables(
array(
'file_extensions' => implode(', ', $fileExtensions)
)
);
return $message;
}
}
<?php
namespace Sirius\Validation\Rule\File;
use Sirius\Validation\Rule\AbstractRule;
class Image extends AbstractRule
{
const OPTION_ALLOWED_IMAGES = 'allowed';
const MESSAGE = 'The file is not a valid image (only {image_types} are allowed)';
const LABELED_MESSAGE = '{label} is not a valid image (only {image_types} are allowed)';
protected $options = array(
self::OPTION_ALLOWED_IMAGES => array( 'jpg', 'png', 'gif' )
);
protected $imageTypesMap = array(
IMAGETYPE_GIF => 'gif',
IMAGETYPE_JPEG => 'jpg',
IMAGETYPE_JPEG2000 => 'jpg',
IMAGETYPE_PNG => 'png',
IMAGETYPE_PSD => 'psd',
IMAGETYPE_BMP => 'bmp',
IMAGETYPE_ICO => 'ico',
);
public function setOption($name, $value)
{
if ($name == self::OPTION_ALLOWED_IMAGES) {
if (is_string($value)) {
$value = explode(',', $value);
}
$value = array_map('trim', $value);
$value = array_map('strtolower', $value);
}
return parent::setOption($name, $value);
}
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
if (! file_exists($value)) {
$this->success = false;
} else {
$imageInfo = getimagesize($value);
$extension = isset($this->imageTypesMap[$imageInfo[2]]) ? $this->imageTypesMap[$imageInfo[2]] : false;
$this->success = ($extension && in_array($extension, $this->options[self::OPTION_ALLOWED_IMAGES]));
}
return $this->success;
}
public function getPotentialMessage()
{
$message = parent::getPotentialMessage();
$imageTypes = array_map('strtoupper', $this->options[self::OPTION_ALLOWED_IMAGES]);
$message->setVariables(
array(
'image_types' => implode(', ', $imageTypes)
)
);
return $message;
}
}
<?php
namespace Sirius\Validation\Rule\File;
use Sirius\Validation\Rule\AbstractRule;
class ImageHeight extends AbstractRule
{
const OPTION_MAX = 'max';
const OPTION_MIN = 'min';
const MESSAGE = 'The file should be at least {min} pixels tall';
const LABELED_MESSAGE = '{label} should be at least {min} pixels tall';
protected $options = array(
self::OPTION_MAX => 1000000,
self::OPTION_MIN => 0,
);
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
if (!file_exists($value)) {
$this->success = false;
} else {
$imageInfo = getimagesize($value);
$height = isset($imageInfo[1]) ? $imageInfo[1] : 0;
$this->success = $height &&
$height <= $this->options[self::OPTION_MAX] &&
$height >= $this->options[self::OPTION_MIN];
}
return $this->success;
}
}
<?php
namespace Sirius\Validation\Rule\File;
use Sirius\Validation\Rule\AbstractRule;
class ImageRatio extends AbstractRule
{
// the image width/height ration;
// can be a number or a string like 4:3, 16:9
const OPTION_RATIO = 'ratio';
// how much can the image ratio diverge from the allowed ratio
const OPTION_ERROR_MARGIN = 'error_margin';
const MESSAGE = 'The image does must have a ratio (width/height) of {ratio})';
const LABELED_MESSAGE = '{label} does must have a ratio (width/height) of {ratio})';
protected $options = array(
self::OPTION_RATIO => 0,
self::OPTION_ERROR_MARGIN => 0,
);
protected function normalizeRatio($ratio)
{
if (is_numeric($ratio) || $ratio == filter_var($ratio, FILTER_SANITIZE_NUMBER_FLOAT)) {
return floatval($ratio);
}
if (strpos($ratio, ':') !== false) {
list($width, $height) = explode(':', $ratio);
return $width / $height;
}
return 0;
}
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
$ratio = $this->normalizeRatio($this->options[self::OPTION_RATIO]);
if (! file_exists($value)) {
$this->success = false;
} elseif ($ratio == 0) {
$this->success = true;
} else {
$imageInfo = getimagesize($value);
if (is_array($imageInfo)) {
$actualRatio = $imageInfo[0] / $imageInfo[1];
$this->success = abs($actualRatio - $ratio) <= $this->options[self::OPTION_ERROR_MARGIN];
} else {
// no image size computed => no valid image
return $this->success = false;
}
}
return $this->success;
}
}
<?php
namespace Sirius\Validation\Rule\File;
use Sirius\Validation\Rule\AbstractRule;
class ImageWidth extends AbstractRule
{
const OPTION_MAX = 'max';
const OPTION_MIN = 'min';
const MESSAGE = 'The image should be at least {min} pixels wide';
const LABELED_MESSAGE = '{label} should be at least {min} pixels wide';
protected $options = array(
self::OPTION_MAX => 1000000,
self::OPTION_MIN => 0,
);
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
if (! file_exists($value)) {
$this->success = false;
} else {
$imageInfo = getimagesize($value);
$width = isset($imageInfo[0]) ? $imageInfo[0] : 0;
$this->success = $width &&
$width <= $this->options[self::OPTION_MAX] &&
$width >= $this->options[self::OPTION_MIN];
}
return $this->success;
}
}
<?php
namespace Sirius\Validation\Rule\File;
use Sirius\Validation\Rule\AbstractRule;
class Size extends AbstractRule
{
const OPTION_SIZE = 'size';
const MESSAGE = 'The file should not exceed {size}';
const LABELED_MESSAGE = '{label} should not exceed {size}';
protected $options = array(
self::OPTION_SIZE => '2M'
);
protected function normalizeSize($size)
{
$units = array( 'B' => 0, 'K' => 1, 'M' => 2, 'G' => 3 );
$unit = strtoupper(substr($size, strlen($size) - 1, 1));
if (! isset($units[$unit])) {
$normalizedSize = filter_var($size, FILTER_SANITIZE_NUMBER_INT);
} else {
$size = filter_var(substr($size, 0, strlen($size) - 1), FILTER_SANITIZE_NUMBER_FLOAT);
$normalizedSize = $size * pow(1024, $units[$unit]);
}
return $normalizedSize;
}
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
if (! file_exists($value)) {
$this->success = false;
} else {
$fileSize = @filesize($value);
$limit = $this->normalizeSize($this->options[self::OPTION_SIZE]);
$this->success = $fileSize && $fileSize <= $limit;
}
return $this->success;
}
}
<?php
namespace Sirius\Validation\Rule;
class FullName extends AbstractRule
{
const MESSAGE = 'This input is not a valid full name (first name and last name)';
const LABELED_MESSAGE = '{label} is not a valid full name (first name and last name)';
/**
* This is not going to work with Asian names, http://en.wikipedia.org/wiki/Chinese_name.
*/
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
$names = explode(' ', $value);
// Each name must be at least 2 characters long.
foreach ($names as $name) {
if (mb_strlen($name) < 2) {
return $this->success = false;
}
}
// Name cannot be longer shorter than 6 characters.
return $this->success = mb_strlen($value) >= 6;
}
}
<?php
namespace Sirius\Validation\Rule;
class GreaterThan extends AbstractRule
{
const OPTION_MIN = 'min';
const OPTION_INCLUSIVE = 'inclusive';
const MESSAGE = 'This input should be greater than {min}';
const LABELED_MESSAGE = '{label} should be greater than {min}';
protected $options = array(
'inclusive' => true
);
protected $optionsIndexMap = array(
0 => self::OPTION_MIN,
1 => self::OPTION_INCLUSIVE
);
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
if (! isset($this->options['min'])) {
$this->success = true;
} else {
if ($this->options['inclusive']) {
$this->success = $value >= $this->options['min'];
} else {
$this->success = $value > $this->options['min'];
}
}
return $this->success;
}
}
<?php
namespace Sirius\Validation\Rule;
class InList extends AbstractRule
{
const OPTION_LIST = 'list';
const MESSAGE = 'This input is not one of the accepted values';
const LABELED_MESSAGE = '{label} is not one of the accepted values';
protected $optionsIndexMap = array(
0 => self::OPTION_LIST
);
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
if (! isset($this->options['list'])) {
$this->success = true;
} else {
if (is_array($this->options['list'])) {
$this->success = in_array($value, $this->options['list']);
}
}
return $this->success;
}
}
<?php
namespace Sirius\Validation\Rule;
class Integer extends AbstractRule
{
const MESSAGE = 'This input must be an integer number';
const LABELED_MESSAGE = '{label} must be an integer number';
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
$this->success = (bool) filter_var($value, FILTER_VALIDATE_INT) || (string) $value === '0';
return $this->success;
}
}
<?php
namespace Sirius\Validation\Rule;
class IpAddress extends AbstractRule
{
const MESSAGE = 'This input is not a valid IP address';
const LABELED_MESSAGE = '{label} is not a valid IP address';
public function validate($value, $valueIdentifier = null)
{
$this->value = $value;
// Do not allow private and reserved range IPs
$flags = FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE;
if (strpos($value, ':') !== false) {
$this->success = (bool) filter_var($value, FILTER_VALIDATE_IP, $flags | FILTER_FLAG_IPV6);
} else {
$this->success = (bool) filter_var($value, FILTER_VALIDATE_IP, $flags | FILTER_FLAG_IPV4);
}
return $this->success;
}
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment