add-wxapp-liche

This commit is contained in:
lccsw
2021-07-06 10:53:22 +08:00
parent 71d5dfb439
commit 01837ba8b1
139 changed files with 9556 additions and 97 deletions
+1 -1
View File
@@ -241,7 +241,7 @@ class Clues extends HD_Controller{
's_id' => $clues_row['s_id'],
'if_driver' => $clues_row['if_driver'],
'admin_id' => $admin_id,
'cf_id' => $clues_row['cf_id'],
'cf_title' => '后台分配',
'p_time' => date('Y-m-d H:i:s'),
'c_time' => time()
];
+1 -1
View File
@@ -136,7 +136,7 @@ $config['subclass_prefix'] = 'HD_';
| Note: This will NOT disable or override the CodeIgniter-specific
| autoloading (application/config/autoload.php)
*/
$config['composer_autoload'] = '';
$config['composer_autoload'] = COMMPATH.'/vendor/autoload.php';
/*
|--------------------------------------------------------------------------
+93
View File
@@ -459,4 +459,97 @@ class Hd extends CI_Controller {
return false;
}
/**
* 上传图片
* @throws Exception
*/
public function upimg(){
$app = $this->input->post('app');
$log_name = "{$app}_upimg.log";
try {
if(!$app){
throw new Exception('参数错误', API_CODE_INVILD_PARAM);
}
//接收图片
if (!$file = $_FILES['img']) {
throw new Exception('请选择图片', API_CODE_INVILD_PARAM);
}
if (!$file['tmp_name']) {//太大的图片上传,这个参数会变成空的
debug_log(json_encode($file), $log_name);
throw new Exception('参数错误', API_CODE_INVILD_PARAM);
}
debug_log("[info]". __FUNCTION__ . ": tmp_name:" . $file['tmp_name'] . ";size:" . filesize($file['tmp_name']), $log_name);
if (!file_exists(TEMP_PATH)){
$oldumask = umask(0);
mkdir(TEMP_PATH, 0777, true);
umask($oldumask);
}
$tmp = TEMP_PATH . md5($file['name'] . uniqid()) . substr($file['name'], strpos($file['name'], '.', strlen($file['name']) - 1));
move_uploaded_file($file['tmp_name'], $tmp);
debug_log("[info]". __FUNCTION__ . "tmp:$tmp;size:" . filesize($tmp), $log_name);
if (!filesize($tmp)) {
throw new Exception('图片有点问题,换个小的试试', API_CODE_INVILD_PARAM);
}
//上传图片到FTP
$res = $this->upload_img_qiniu($tmp,"{$app}/");
if (!$res) {
throw new Exception('上传失败', API_CODE_FAIL);
}
$data['full_url'] = build_qiniu_image_url($res['photo']);
$data['url'] = $res['photo'];
debug_log("[info]". __FUNCTION__ . "full_url:" . $data['full_url'], $log_name);
$this->print_return($data);
} catch (Exception $e) {
$message = $e->getMessage();
$this->print_return($this->return_error($e->getCode(), $message));
}
}
/**
* @param string $file 上传的文件
* @param string $path 要保存的目录
* @param string $filename 原始文件名称
* @throws Exception
* @return array
*/
private function upload_img_qiniu($file, $path = '',$filename = ''){
$phoId = md5(uniqid().mt_rand(0,10000).time());
$filename = $filename ? $filename : $file;
$ext_arr = explode(".", $filename);
$ext = count($ext_arr)>1?$ext_arr[count($ext_arr)-1]:'jpg';
if (is_uploaded_file($file)) {
//上传图片
$oriPath = TEMP_PATH . '/p_' . $phoId . '_ori.' . $ext;
move_uploaded_file($file, $oriPath);
} else {
$oriPath = $file;
}
$oriKey = 'p_' . $phoId . '.' . $ext;
// 上传到七牛后保存的文件名
$photo = $path .date('Ym') . "/" . $oriKey;
//上传图片到FTP
$this->load->library('qiniu');
$res= $this->qiniu->save($photo, file_get_contents($oriPath));
$img_size = getimagesize($oriPath);
$file_size = filesize($oriPath);
$size = "{$img_size[0]},{$img_size[1]},{$file_size}";
unlink($oriPath);
if ($res) {
$size = getimagesize($res['url']);
return array('photo' => $res['file'], 'size' => $size);
} else {
return array();
}
}
}
+82
View File
@@ -0,0 +1,82 @@
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
use Gregwar\Image\Image;
class Test extends CI_Controller {
public function index(){
$name= 'car_fh';
$url = "https://liche-api-dev.xiaoyu.com/wxapp/licheb/protocol/".$name;
$path = FCPATH.'temp/pdf/';
$filename = $name.'.pdf';
if (!file_exists($path)){
$oldumask = umask(0);
mkdir($path, 0777, true);
umask($oldumask);
}
$arrContextOptions=array(
"ssl"=>array(
"verify_peer"=>false,
"verify_peer_name"=>false,
),
);
$html = file_get_contents($url,false,stream_context_create($arrContextOptions));
require_once COMMPATH.'/third_party/TCPDF/tcpdf.php';
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT,true, 'UTF-8', false);
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor("jmcx");
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(false);
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
$pdf->SetMargins(PDF_MARGIN_LEFT, 5,PDF_MARGIN_RIGHT);
$pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
$pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
$pdf->SetFont('stsongstdlight', '', 10); //设置中文显示
$pdf->AddPage();
$pdf->writeHTML($html, true, false, true, false, '');
$pdf->Output($path.$filename,'F');
}
public function pdf2img(){
$pdf = 'http://liche-api-dev.xiaoyu.com/temp/pdf/car_fh.pdf';
$pdf2img_url = 'http://liche-api-dev.xiaoyu.com/jar/pdf2img';
$this->load->library('mycurl');
$url = $pdf2img_url.'?furl='.$pdf;
$res = $this->mycurl->httpGet($url);
var_dump($res);
}
public function save_img(){
$img = 'https://liche-api-dev.xiaoyu.com/pdf2img/2021-07-07/1889917037729102438059_0.png';
if(!$_FILES['file']){
echo '参数错误';exit;
}
$this->load->library('receiver/sign_entity');
$res = $this->sign_entity->merge($img,$_FILES['file'],1050,1550,300); //协议
//$res = $this->sign_entity->test($img,$base64_img,1050,200,300); //整车
//$res = $this->sign_entity->test($img,$base64_img,1050,400,300); //确认单
//$res = $this->sign_entity->test($img,$base64_img,300,1400,'','',false); //车辆交接信息
echo $res;
}
public function img(){
//签名文件
$img = 'https://liche-api-dev.xiaoyu.com/pdf2img/2021-07-07/1889917037729102438059_0.png'; //协议
//$img = 'https://liche-api-dev.xiaoyu.com/pdf2img/2021-07-08/1964010084089102318048_2.png'; //整车
//$img = 'https://liche-api-dev.xiaoyu.com/pdf2img/2021-07-08/1964942930570102661389_0.png'; //确认单
//$img = 'https://liche-api-dev.xiaoyu.com/pdf2img/2021-07-08/1965121467553102596576_0.png'; //车辆交接信息
//用户签名
$base64_img = "iVBORw0KGgoAAAANSUhEUgAAAXcAAAKdCAMAAADvKdm1AAAAAXNSR0IB2cksfwAAAFFQTFRFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXKkVQgAAABt0Uk5TADCA/99A78/Q8CAQwKBwv+BQkLBgr59/P2+PuKEyZQAAC7pJREFUeJzt3ely6zYMhuHKuy0v8ZJz2t7/hdaCvCTxJskkPvXgff51ppPSGJUEQVD66y8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+J8oCvUIQhoMh6OxehABTYbD4VQ9iIBmx7jP1YMIqHreB+pBxLM4hn1YqkcRz/gY9qV6EAEd05nhSj2IgFZM7xLLY9xJ392V1bK6UI8inhXZu0JRPe5r9Sji2RzD/qEeRDzbIauqwohNk8KAZEahrEpiO/Uo4qke9zklMW8lFWAJHncJHncNHncJHncNHncJHncNHncJHncNHncNHneJMY+7xI6mGYnqvGOrHkQ8BT2REutj2PfqQQQ0Pcb9oB5EPAuOVSUOx7DP1IMIaE+PmIK1onJ30t2W3jyJFV0zClYCpifSHR3vEnS8a9DxLnGg412hHFESU6DjXcIqYpyruvusFlUOPLxVx9kU3v1xjUxiTSFSwQozdG+0keRVgwealVqyrLtXRiG6bybqMN+aRAj8TB3lOyK8crJczdVhvkFDQjPVcUeq3H07G35EmGcSsMoMsXJXpUQcd7izPROVGXfsmTSqihh1d3f2HjGOmdxVTQRUxNxZzwwFYHcp90xobHHa2scoIvbHpYw8Ya5xtLiWkUek8H4+v1QRN+rBxGG5e9UAXF2O58KBl/LavFF92oAijZPdNXcvP1hbvViL2LkyU1THVhEO6PSm3+ruB6Z4H5a6f7lmsOfYycPiZ4tYPcWTxWe2uTnuKMji8zvcmVUGXxda5GCHqjd1yCVF4czshvDNKVM5p1CT1fjBjGKFg0//8QRhBYK73XQ76gUZDR7P41Wf64Rj7iyKJ1tTqxeQTGZh7yF4tHquz7VhJLZ+XhBYMtNkYan7k/cQLJhpsvh81Q/JTJPD+HVUmWkyeJi6XzHTpPckdb9ipklt0exUiZkmsduq+13MNGltm57lMdOkdL/qfhczTUK75nc7FvR1JFO0Ocdbc+iXyveGmVf2HPqlsf7RMPMCh35p2CzT5r2cVlH4lW08QVifUrv7wTs6yN5WTtufnJYzOsje9dklPaGD7F02ZbS/Hsy29T3WlTfrMGPQQfYOmy86vXODbesb6lSm21O75TpCV11SmatVu90WLjqlMhdcR+ioYypzMaZXtYvOqczFgF7V9or25YEbM5LJtqzjumMqc2HJJJeK29gkmSNsrpqytjaW6n0PNsWzfWrKntMkb7FaUYtvztbURN8GmnHc2lSSNfXyx2Zkkw2lWVPP7AIOHTWvpX6HUsHa2kS6NfXbX2SKfy7lmnq2pzT5StI19fJHP+ioeSHtmnpGafKFXO8lpDT5VPo19Yxr9E/kWFNPOOd+LMuaekYy+VCeNfWMZPKBzO/6JZm8L9+aekIyeY9FJe934UkmbxVvtIY1xjn3T/X3C3I/i5xz//BeR15ztoawtp7VYff4CNaaBoMvfnmF/XTOTVJjLOxe31je02Bwsn67EbKN+pybKzj1Wuf4HVXbt5LG12H3zO2swSB6Gm9hdw6CNRjETuPrsHv/Tx8+jdeEPXwarwp78DReF/bQabwy7IHT+MKlBPlQ1DTeDrGVvztoGp/3ELuJkGl8Hz5YG/DWWfZD7EbC3To75D/EbiTYrTP/WtgjoW6dSRP37yLdOutR2CPdOutV2MO8em877VfYT7XJ3+pR5DbqW9hPr96b/uGdwj2silgX2TGd1Ke1GW1nw3nf3tx7qAM/+f1HR76HSts/HSP/h082/TO2PH44Uo8jnvW8fytPCCWB19j2L8WNwXbSvGHVH3dcRQZRimQ9U/JZRQ2+TyGyDHbi2hdVkWyuHkREh+GcKg0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBmfxfqEYS04+t6CvZlePUgAqq+VL9UDyIe+9QYnwByNzmGfa8eRDzjY9jnfDvV3TGZGa7UgwhodIz7Vj2IeBbVqso0427Nqiqx5Hu1CmU1zfBhbHfVl+Bn6kEEtDrGfaceRDxltVmlCOyummb4Kra/atM0UA8ingObJokNtRmFMcm7xJ4agcKCgyaJFeeqClaaoX/D3eAY9g/1IOKxEgGPu7sD59kSlAgk2DNpUCKQYM+kwZ5JgiRSgz2TBkmkBHsmDZJICfZMGiSREuyZNEgiNdgzSZBEakxpAVYoSCIlVjQrKVglknuT7tYkkRJUIiXGdLxLrKhEKlCa0aA0ozGiNKOwpTQjwfmehK2q3M52t+N8T4EmMY0VLyNQsMI7r1Zyt2HPpHCgRKBQjkhmFAYcqyosJpx3KHxSmVEY8y4CiSmviVQgh5Swwgz1X3dVHXJODunNyu7kkO6sMEMO6c1ySDoi3VGYkRhwqKqwIIeUoDAjseVwT4HTDo0di6rCmJ2qxJQWAoUB5V8FUneNDam7woF6mIIdMpG6u1txyKRA6i5hBQI6N9xRdZewOwa8VMkdR9kSa1J3BSsQTP/meXdWlSErIx55T4Ph2YRH3o/tmPbLIRsnV7ZjmpeL1YwH3tOv82FHOeeB97O97piqeX5CZcyFpZCnuow98J/a8USx+VqXYfvkZf29PaxaWkcsrdlZOWz5458pj+VWTn+eZNMv5mF3M5+XH1WlRjWeIGyj+qNfhn7g7KyB4KbovqdnLLPPu3P5okriJ0zx2awf1MGsfYnA52Ip490GAgv8lCw+C6sPPGhTWhH4XCxzf/iCGQv8xnVAQXw+P+SwQ5BfjuMJYncnc/+qnBH4DGzlnD2bwOvA86KrpCyVeXHBoJgT+MTqVOZVgl6wf0rreSpzZdUbivHJvEhlrg5kkwm9SmV+/qucgiTxOpX5Ysnamki9pjadtO0UhLU1gU2TVObKkhrW1rcN2p4msbamYBumdt9sZm1N4KZ9oAHW1rfdtg80YGsrgX/DvfaBBqjUvMf63Lvc2bO1lcB3delzb43Av2H7RmJC4Dsrv/S5t0fgu7rfpNQYge/mUZNSYwS+i+L9dykR+Pbqq5Jv3hgj8K1tkkSMwLeUqrZF4FuxcCV5UV4deC78NVLcvV7QDT3ajdVraqpQEfim0qypFwS+meTnRXXgOXJ9Lt2aesGthNfsqCP1e/II/CtFow7U1gj8c9aklGOfY3dceWHKA00bfzv8Za6DPFaHPc9nIwj8Y7/yhZ3AP2Zhz/di8ZLujrvWbfqtu6Ct5h7bL+X9Ng2Bv9Xs6tibCPyNb2/Jy2bLOch3P96Slw0HUN8s3L7EROC/2iToHmiIwF95zTKGwJ9lKLm//M8R+FPm7vhWawJfEUSBwItiQOBFEYgeeNnvjx144a+PHHjpb48bePEvjxr4f9S/O2TgFxv9rw4X+O35u4bi3xwt8KM66nP5L64D/696GF7sjRnDZQ++NFYH/jNIC992dnzY+/FNjoOduU578AgEUx92T/hAiLe6kyzQ6toXpbVp08Pnzw4ah5sgq2uPbG2SH3H7zFthqe2EG8beyvoz6f+oxxHPaXVlkvdW7125fuZuXG+hWF29LWwLNWEL5a3cxypQ9seOSV7jwCSvUW+hyOTdnbZQZPLuBkMOQyTqOhnlGndFfRjyWz2OcE6HIVFOvHukPgyhJu/uVK6hauCtZJIXoSYvQk1epODEW+NUk2cL5e1UriGtcUc/mciBfjKNLd3aGqd+MtIab3Rri5wKlATe3YC0RuNA4DXqyjD5pLu6WkOZzF197joln/RW55Mk8u7qMhn3Xf2RyIusmGo0DmQ1Ggc2UBorpngJSyeZ4v3ZzpUp3h9TvAhTvAZTvIhN8SOmeHc2xW/Uowgo+TfY0cyStVWi/GBtlWD7JML2SYTtk0a9fVKPIiCb4lla/VXvaOrHy71jqS5279WDCKhggteoMhr1GCIi7hrEXYO4axB3DeKu8TEcztRjiGg7++C1EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoLf+A6jRZVspl5i5AAAAAElFTkSuQmCC";
$this->load->library('receiver/sign_entity');
$res = $this->sign_entity->test($img,$base64_img,1050,1550,300); //协议
var_dump($res);exit;
}
}
+39 -1
View File
@@ -5,7 +5,7 @@ defined('WXAPP_APP') OR exit('No direct script access allowed');
* Created by Vim
* User: lcc
* Desc: 车系信息
* Date: 2020.06.23
* Date: 2021.06.23
* Time: 14:08
*/
require_once APPPATH.'controllers/wxapp/Wxapp.php';
@@ -59,5 +59,43 @@ class Series extends Wxapp{
}
return $list;
}
//获取车系属性
public function get_attrs(){
$s_id = $this->input_param('id');
$type = $this->input_param('type');
$page = $this->input_param('page');
$size = $this->input_param('size');
!$page && $page = 1;
!$size && $size = 20;
$this->load->model('auto/auto_attr_model');
$where = [
's_id' => $s_id
];
strlen($type) && $where['type'] = $type;
$count = $this->auto_attr_model->count($where);
$rows = $this->auto_attr_model->select($where,'id desc',$page,$size,'id,title,type,jsondata');
$lists = [];
if($rows){
foreach($rows as $key=>$val){
$jsodnata = json_decode($val['jsondata'],true);
$temp = [
'id' => $val['id'],
'title' => $val['title']
];
if($val['type']==1){
$temp['price'] = $jsodnata['price'];
$temp['deposit'] = $jsodnata['deposit'];
}
$lists[] = $temp;
}
}
$data = [
'list' => $lists,
'total' => $count
];
return $data;
}
}
+3 -3
View File
@@ -5,7 +5,7 @@ defined('WXAPP_APP') OR exit('No direct script access allowed');
* Created by Vim
* User: lcc
* Desc: 预约信息
* Date: 2020.06.23
* Date: 2021.06.23
* Time: 14:08
*/
require_once APPPATH.'controllers/wxapp/Wxapp.php';
@@ -124,7 +124,7 @@ class Aptinfo extends Wxapp{
$where = [
'cf_id' => $cf_id,
'cf_uid' => $this->session['uid'],
'cf_app' => $this->app_id,
'app_id' => $this->app_id,
'cf_platform' => $cf_platform,
];
$row = $this->clues_model->get($where);
@@ -134,7 +134,7 @@ class Aptinfo extends Wxapp{
'mobile' => $this->session['mobile'],
'cf_uid' => $this->session['uid'],
'cf_id' => $cf_id,
'cf_app' => $this->app_id,
'app_id' => $this->app_id,
'if_driver' => 1,
'cf_platform' => $cf_platform,
'jsondata' => json_encode($jsondata,JSON_UNESCAPED_UNICODE),
+2 -1
View File
@@ -5,7 +5,7 @@ defined('WXAPP_APP') OR exit('No direct script access allowed');
* Created by Vim
* User: lcc
* Desc: 订车信息
* Date: 2020.06.23
* Date: 2021.06.23
* Time: 14:08
*/
require_once APPPATH.'controllers/wxapp/Wxapp.php';
@@ -106,6 +106,7 @@ class Car extends Wxapp{
'mobile' => $this->session['mobile'],
'cf_uid' => $this->session['uid'],
'cf_id' => 2,
'app_id' => $this->app_id,
'cf_platform' => $cf_platform,
'jsondata' => json_encode($jsondata,JSON_UNESCAPED_UNICODE),
'c_time' => time()
+200
View File
@@ -0,0 +1,200 @@
<?php
defined('WXAPP_APP') OR exit('No direct script access allowed');
/**
* Created by Vim
* User: lcc
* Date: 2021/07/12
* Time: 16:08
*/
require_once APPPATH.'controllers/wxapp/Wxapp.php';
class Contract extends Wxapp{
function __construct($inputs, $app_key){
parent::__construct($inputs, $app_key);
$this->login_white = array();//登录白名单
$this->check_status = array();//用户状态校验
$this->check_mobile = array();//需要手机号
$this->check_headimg =array();//授权微信信息
$this->load->model('receiver/order/receiver_orders_model','orders_model');
$this->load->model('receiver/order/receiver_order_signs_model','signs_model');
$this->load->model('receiver/order/receiver_order_contracts_model','contracts_model');
}
protected function get(){
$id = $this->input_param('id');
$type = $this->input_param('type');
!strlen($type) && $type = 0;
$row = $this->orders_model->get(['id'=>$id,'mobile'=>$this->session['mobile']]);
$type_arr = $this->contracts_model->get_types();
if(!$row || !$type_arr[$type]){
throw new Exception('参数错误', API_CODE_INVILD_PARAM);
}
$contract = $this->contracts_model->get(['type'=>$type,'o_id'=>$id]);
$this->load->library('receiver/orders_entity');
$this->load->library('pdf');
$h5_url = $this->orders_entity->get_contract_h5($id,$type,1);
if(!$contract){
$cid = create_order_no(350200,$this->app_key,2);
$add_data = [
'cid' => $cid,
'o_id' => $id,
'type' => $type,
'c_time' => time()
];
$con_id = $this->contracts_model->add($add_data);
if(!$con_id){
throw new Exception('创建合同失败', API_CODE_INVILD_PARAM);
}
//html转pdf
$save_path = 'data/contracts/'.date('Ymd');
$filename = $cid.'.pdf';
$c_res = $this->pdf->html2pdf($h5_url,FCPATH.$save_path,$filename);
$update = [
'file' => $save_path.'/'.$filename
];
$this->contracts_model->update($update,['id'=>$con_id]);
}else{
if(!$contract['status'] && date('Ymd')!=date('Ymd',$contract['c_time'])){ //更新合同文件日期
//html转pdf
@unlink(FCPATH.$contract['file']);
$save_path = 'data/contracts/'.date('Ymd');
$filename = $contract['cid'].'.pdf';
$c_res = $this->pdf->html2pdf($h5_url,FCPATH.$save_path,$filename);
$update = [
'file' => $save_path.'/'.$filename,
'c_time' => time()
];
$this->contracts_model->update($update,['id'=>$contract['id']]);
}
}
$data = [
'url' => $h5_url,
'img' => 'https://qs.haodian.cn/wechat_app/liche/mine/he-demo-1.jpg',
];
return $data;
}
protected function post(){
$id = $this->input_param('id');
$type = $this->input_param('type');
$img = $this->input_param('img');
$row = $this->contracts_model->get(['type'=>$type,'o_id'=>$id]);
if($type==2){
$img = 'https://qimg.haodian.cn/hdi/liche/202107/p_2ded4e70664dc34e8ac5fa8e399c3212.png';
}
if(!$row['file'] || !$img){
throw new Exception('参数错误', API_CODE_INVILD_PARAM);
}
if($row['status']==1){
throw new Exception('已签名', API_CODE_INVILD_PARAM);
}
//pdf转图片
$pdf_url = http_host_com('api').'/'.$row['file'];
$this->load->library('pdf');
$pdf = new Pdf(true);
$imgs = $pdf->pdf2img($pdf_url);
if(!$imgs){
throw new Exception('签名失败,图片转换失败', API_CODE_INVILD_PARAM);
}
$this->load->library('receiver/sign_entity');
switch($type){
case 0: //整车
$sign_img = array_pop($imgs);
$res = $this->sign_entity->merge($sign_img,$img,1050,200,300);
//$res = $this->sign_entity->test($sign_img,$base64_img=555,1050,200,300);
if(!$res){
throw new Exception('签名失败', API_CODE_INVILD_PARAM);
}
$imgs[] = http_host_com('api').'/'.$res;
$imgs = $this->up_qiniu($imgs,$res);
$update = [
'imgs' => json_encode($imgs,JSON_UNESCAPED_UNICODE),
'sign_time' => date('Y-m-d H:i:s'),
'status' => 1
];
$result = $this->contracts_model->update($update,['id'=>$row['id']]);
if($result){
throw new Exception('签名成功', API_CODE_SUCCESS);
}else{
throw new Exception('签名失败', API_CODE_INVILD_PARAM);
}
break;
case 1: //协议
$sign_img = array_pop($imgs);
$res = $this->sign_entity->merge($sign_img,$img,1050,1550,300);
//$res = $this->sign_entity->test($sign_img,$base64_img=555,1050,1550,300);
if(!$res){
throw new Exception('签名失败', API_CODE_INVILD_PARAM);
}
$imgs[] = http_host_com('api').'/'.$res;
$imgs = $this->up_qiniu($imgs,$res);
$update = [
'imgs' => json_encode($imgs,JSON_UNESCAPED_UNICODE),
'sign_time' => date('Y-m-d H:i:s'),
'status' => 1
];
$result = $this->contracts_model->update($update,['id'=>$row['id']]);
if($result){
$this->signs_model->update(['status'=>1],['o_id'=>$id]);
//生成定金订单
$this->load->library('receiver/orders_entity');
$this->orders_entity->c_order($id,$this->app_id,$this->session);
throw new Exception('签名成功', API_CODE_SUCCESS);
}else{
throw new Exception('签名失败', API_CODE_INVILD_PARAM);
}
break;
case 2: //确认信息
$sign_img = array_pop($imgs);
$res = $this->sign_entity->merge($sign_img,$img,1050,400,300);
//$res = $this->sign_entity->test($sign_img,$base64_img=555,1050,400,300); //确认单
if(!$res){
throw new Exception('签名失败', API_CODE_INVILD_PARAM);
}
$imgs[] = http_host_com('api').'/'.$res;
$imgs = $this->up_qiniu($imgs,$res);
$update = [
'imgs' => json_encode($imgs,JSON_UNESCAPED_UNICODE),
'sign_time' => date('Y-m-d H:i:s'),
'status' => 1
];
$result = $this->contracts_model->update($update,['id'=>$row['id']]);
if($result){
$this->orders_model->update(['status'=>3],['id'=>$id]);
throw new Exception('签名成功', API_CODE_SUCCESS);
}else{
throw new Exception('签名失败', API_CODE_INVILD_PARAM);
}
break;
case 3: //交接信息
break;
default:
throw new Exception('未知签名类型', API_CODE_INVILD_PARAM);
}
}
//图片上传七牛
private function up_qiniu($imgs,$file){
$this->load->library('qiniu');
//上传七牛并保存
foreach($imgs as $key=>$val){
$file_name = md5($val).'.jpg';
$result = $this->qiniu->fetch($val,$file_name);
if($result){
$imgs[$key] = $result['file'];
if (strpos($val, $file) !== false) {
@unlink(FCPATH.$file);
}
}
}
return $imgs;
}
}
+1 -1
View File
@@ -6,7 +6,7 @@ require_once APPPATH.'controllers/wxapp/Wxapp.php';
/**
* Created by Vim
* User: lcc
* Date: 2020.06.23
* Date: 2021.06.23
* Time: 14:08
*/
class Protocol extends Wxapp{
+126 -47
View File
@@ -1,12 +1,11 @@
<?php
defined('WXAPP_APP') OR exit('No direct script access allowed');
require_once APPPATH.'controllers/wxapp/Wxapp.php';
require_once APPPATH.'controllers/wxapp/Wxapp.php';
/**
* Created by Vim
* User: lcc
* Date: 2020.06.23
* Date: 2021.06.23
* Time: 14:08
*/
class User extends Wxapp{
@@ -177,51 +176,131 @@ class User extends Wxapp{
* @return array
*/
protected function get_my(){
$progress = [
[
"title"=>"已签合同",
"icon"=>"icon-qiandinghetong",
"state"=>1//0未开启/1已开启/2当前开启
],
[
"title"=>"已交定金",
"icon"=>"icon-yijiaodingjin",
"state"=>1
],
[
"title"=>"办理按揭",
"icon"=>"icon-banlianjie",
"state"=>2
],
[
"title"=>"配车准备",
"icon"=>"icon-peichezhunbei",
"state"=>0
],
[
"title"=>"车辆确认",
"icon"=>"icon-cheliangqueren",
"state"=>0
],
[
"title"=>"已开发票",
"icon"=>"icon-yikaifapiao",
"state"=>0
],
[
"title"=>"保险上牌",
"icon"=>"icon-baoxianshangpai",
"state"=>0
],
[
"title"=>"恭喜提车",
"icon"=>"icon-gongxitiche",
"state"=>0
],
];
$mobile = $this->session['mobile'];
$this->load->model('receiver/order/receiver_orders_model','orders_model');
$row = $this->orders_model->get(['mobile'=>$mobile,'status>-1'=>null]);
$progressOpt = $progress = [];
if($row){
$progressOpt = [];
$progress_arr = [
[
"id" => 1,
"title"=>"已签合同",
"icon"=>"icon-qiandinghetong",
"key" => 0,
"state"=>2//0未开启/1已开启/2当前开启
],
[
"id" => 2,
"title"=>"已交定金",
"icon"=>"icon-yijiaodingjin",
"key" => 0,
"state"=>0
],
[
"id" => 3,
"title"=>"办理按揭",
"icon"=>"icon-banlianjie",
"key" => 1,
"state"=>0
],
[
"id" => 4,
"title"=>"配车准备",
"icon"=>"icon-peichezhunbei",
"key" => 2,
"state"=>0
],
[
"id" => 5,
"title"=>"车辆确认",
"icon"=>"icon-cheliangqueren",
"key" => 2,
"state"=>0
],
[
"id" => 6,
"title"=>"已开发票",
"icon"=>"icon-yikaifapiao",
"key" => 3,
"state"=>0
],
[
"id" => 7,
"title"=>"保险上牌",
"icon"=>"icon-baoxianshangpai",
"key" => 4,
"state"=>0
],
[
"id" => 8,
"title"=>"恭喜提车",
"icon"=>"icon-gongxitiche",
"key" => 5,
"state"=>0
],
];
if($row['payway']){ //全款
unset($progress_arr[2]);
}
$progress = [];
$this->load->model('receiver/order/receiver_order_signs_model');
$this->load->model('receiver/order/receiver_order_contracts_model');
$this->load->model('receiver/order/receiver_order_loans_model');
$this->load->model('receiver/order/receiver_order_ckcars_model');
$sign_row = $this->receiver_order_signs_model->get(['o_id'=>$row['id']],'status');
$ckcar_row = $this->receiver_order_ckcars_model->get(['o_id'=>$row['id']],'status');
foreach($progress_arr as $key=>$val){
if($row['status']>$val['key']){
$state = 1;
}elseif($row['status']==$val['key']){
switch($val['key']){
case 0:
$state = 0;
if(!$sign_row['status']){//未签名
$count = $this->receiver_order_contracts_model->count(['o_id'=>$row['id'],'type in (0,1)','status'=>1]);
if($count>0){
$url = '/pages/mine/signContract/daiLi?id='.$row['id'];
}else{
$url = '/pages/mine/signContract/zhengChe?id='.$row['id'];
}
$progressOpt = ['title'=> '合同签订','url'=>$url];
$val['id']== 1 && $state = 2;
}elseif($sign_row['status']==1){ //未交定金
$val['id']==1 && $state = 1;
$val['id']==2 && $state = 2;
$progressOpt = ['title'=> '交定金','url'=>'/pages/order/index?typeId=1'];
}else{ //已交定金
$state = 1;
}
break;
case 2:
if($ckcar_row['status']){
if($val['id']==5){
$state = 2;
$progressOpt = ['title'=> '合同签订','url'=>'/pages/mine/signContract/queRen?id='.$row['id']];
}else{
$state = 1;
}
}else{
$state = $val['id'] == 4 ? 2:0;
}
break;
default:
$state = 2;
}
}else{
$state = 0;
}
$progress[] = [
'title' => $val['title'],
'icon' => $val['icon'],
'state' => $state
];
}
}
$data = [
'progressOpt' => ['title'=> '办理按揭','url'=>'/page/..'],
'progressOpt' => $progressOpt,
'progress' => $progress,
'about' => [
['title'=>'我的爱车','icon'=>'https://qs.haodian.cn/wechat_app/liche/mine/list-icon-1.png','url'=>'/pages/mine/myCar/index'],
+271
View File
@@ -0,0 +1,271 @@
<?php
defined('WXAPP_APP') OR exit('No direct script access allowed');
/**
* Created by Vim
* User: lcc
* Date: 2021/07/09
* Time: 14:08
*/
require_once APPPATH.'controllers/wxapp/Wxapp.php';
class Cusorder extends Wxapp{
function __construct($inputs, $app_key){
parent::__construct($inputs, $app_key);
$this->login_white = array();//登录白名单
$this->check_status = array();//用户状态校验
$this->check_mobile = array();//需要手机号
$this->check_headimg =array();//授权微信信息
$this->load->model('receiver/receiver_customers_model','customers_model');
$this->load->model('receiver/order/receiver_orders_model','orders_model');
$this->load->model('receiver/order/receiver_order_signs_model','order_signs_model');
$this->load->model('auto/auto_series_model');
$this->load->model('auto/auto_brand_model');
$this->load->model('auto/auto_attr_model');
}
protected function get(){
$id = $this->input_param('id');
if($id){
return $this->detail($id);
}else{
return $this->lists();
}
}
//创建订单
protected function post(){
$cus_id = $this->input_param('cus_id');
$car_id = $this->input_param('car_id');
$color_id = $this->input_param('color_id');
$v_id = $this->input_param('v_id');
$price = $this->input_param('price');
$deposit = $this->input_param('deposit');
$payway = $this->input_param('payway');
$order = $this->orders_model->get(['rid'=>$cus_id]);
if($order){
throw new Exception('该客户订单已存在', ERR_PARAMS_ERROR);
}
$row = $this->customers_model->get(['id'=>$cus_id]);
$series_row = $this->auto_series_model->get(['id'=>$car_id]);
if(!$row || !$series_row){
throw new Exception('参数错误', ERR_PARAMS_ERROR);
}
$where = [
"id in ($v_id,$color_id)" => null
];
$attr_row = $this->auto_attr_model->map('id','',$where);
if($attr_row[$color_id]){
$color_row = $attr_row[$color_id][0];
$color_row['jsondata'] = json_decode($color_row['jsondata'],true);
}
if($attr_row[$v_id]){
$version_row = $attr_row[$v_id][0];
$version_row['jsondata'] = json_decode($version_row['jsondata'],true);
}
$car_json = [
'c_id' => $color_id,
'v_id' => $v_id,
'color' => isset($color_row) ? $color_row : '',
'version' => isset($version_row) ? $version_row : ''
];
$data = [
'rid' => $cus_id,
'sid' => create_order_no(350200,$this->app_key),
'name' => $row['name'],
'mobile' => $row['mobile'],
'brand_id' => $series_row['brand_id'],
's_id' => $series_row['id'],
'v_id' => $v_id,
'admin_id' => $this->session['uid'],
'car_json' => json_encode($car_json,JSON_UNESCAPED_UNICODE),
'price' => $price,
'deposit' => $deposit,
'c_time' => time()
];
$payway && $data['payway'] = 1;
$o_id = $this->orders_model->add($data);
if($o_id){
$sign_data = [
'o_id' => $o_id,
'c_time' => time()
];
$this->order_signs_model->add($sign_data);
return ['id'=>$o_id];
}else{
throw new Exception('创建失败', ERR_PARAMS_ERROR);
}
}
//修改订单信息
protected function put(){
$id = $this->input_param('id');
$payway = $this->input_param('payway');
$row = $this->orders_model->get(['id'=>$id]);
if(!$row){
throw new Exception('订单不存在', ERR_PARAMS_ERROR);
}
$result = false;
$up_data = [];
if(strlen($payway)){
if($row['status']>0){
throw new Exception('修改失败,已签订合同', ERR_PARAMS_ERROR);
}
$up_data['payway'] = $payway;
}
if($up_data){
$result = $this->orders_model->update($up_data,['id'=>$id]);
}
if($result){
throw new Exception('修改成功', API_CODE_SUCCESS);
}else{
throw new Exception('修改失败', ERR_PARAMS_ERROR);
}
}
//订单列表头部
protected function get_tabs(){
$rows = $this->orders_model->get_status();
$lists = [];
if($rows){
foreach($rows as $key=>$val){
$lists[] = [
'key' => $key,
'name' => $val
];
}
}
return $lists;
}
//订单列表
private function lists(){
$group_id = $this->session['group_id'];
$uid = $this->session['uid'];
$keyword = $this->input_param('keyword');
$status = $this->input_param('status');
if($group_id==3){ //掌柜
$where = [];
}elseif($group_id==2){ //店长
$sub_user = $this->app_user_model->select(['pid'=>$uid],'','','','id');
$ids_arr = array_column($sub_user,'id');
$ids_arr[] = $uid;
$ids = implode(',',$ids_arr);
$where = [
"admin_id in ($ids)" => null
];
}else{ //销售
$where = [
'admin_id' => $uid
];
}
if($keyword){
$where["(name={$keyword}) or (mobile={$keyword})"] = null;
}
strlen($status) && $where['status'] = $status;
$fileds = 'id,name,mobile,car_json,brand_id,s_id,deposit,payway,if_cnum,status,c_time';
$count = $this->orders_model->count($where);
$lists = [];
if($count){
$rows = $this->orders_model->select($where,'id desc',$page,$size,$fileds);
//品牌车型
$brand_arr = array_unique(array_column($rows,'brand_id'));
$brand_ids = implode(',',$brand_arr);
if($brand_ids){
$where = [
"id in ({$brand_ids})" => null
];
$brands = $this->auto_brand_model->map('id','',$where,'','','','id,name');
}
//车系车型
$series_arr = array_unique(array_column($rows,'s_id'));
$series_ids = implode(',',$series_arr);
if($series_ids){
$where = [
"id in ({$series_ids})" => null
];
$series = $this->auto_series_model->map('id','',$where,'','','','id,name');
}
$status_arr = $this->orders_model->get_status();
foreach($rows as $key=>$val){
$car_json = json_decode($val['car_json'],true);
$color = isset($car_json['color']) ? $car_json['color']['title'] : '';
$version = isset($car_json['version']) ? $car_json['version']['title'] : '';
$brand_name = isset($brands[$val['brand_id']]) ? $brands[$val['brand_id']][0]['name'] : '';
$serie_name = isset($series[$val['s_id']]) ? $series[$val['s_id']][0]['name'] : '';
$other_data = [
'品牌车型' => "{$brand_name}{$serie_name}-{$color}-{$version}",
'付款方式' => $val['payway']?'全款':'分期',
'代办车牌' => $val['if_cnum']?'需要':'不需要',
'定金金额' => $val['deposit'],
'订单日期' => date('Y-m-d',$val['c_time']),
];
$lists[] = [
'id' => $val['id'],
'name' => $val['name'],
'mobile' => mobile_asterisk($val['mobile']),
'status_name' => $status_arr[$val['status']],
'other_data' => $other_data,
];
}
}
$data = [
'list' => $lists,
'total' => $count
];
return $data;
}
//订单详情
private function detail($id){
$row = $this->orders_model->get(['id'=>$id]);
if(!$row){
throw new Exception('订单不存在', ERR_PARAMS_ERROR);
}
$brand = $this->auto_brand_model->get(['id'=>$row['brand_id']],'name');
$series = $this->auto_series_model->get(['id'=>$row['s_id']],'name');
$car_json = json_decode($row['car_json'],true);
$color = isset($car_json['color']) ? $car_json['color']['title'] : '';
$version = isset($car_json['version']) ? $car_json['version']['title'] : '';
$loan_data = [];
if($row['payway'] && $row['status']>=1){
$this->load->model('receiver/order/receiver_order_loans_model','order_loans_model');
$loan = $this->order_loans_model->get(['o_id'=>$row['id']]);
}
$car_data = [
'车辆名称' => $brand['name'].$series['name'],
'车辆级别' => $version,
'颜色' => $color,
'车辆指导价格' => $row['price'],
'定金' => $row['deposit']
];
$data = [
'id' => $id,
'name' => $row['name'],
'mobile' => mobile_asterisk($row['mobile']),
'payway' => $row['payway'],
'car_data' => $car_data,
'loan_data' => $loan_data
];
return $data;
}
}
@@ -0,0 +1,80 @@
<?php
defined('WXAPP_APP') OR exit('No direct script access allowed');
/**
* Created by Vim
* User: lcc
* Date: 2021/06/23
* Time: 14:08
*/
require_once APPPATH.'controllers/wxapp/Wxapp.php';
class Customerlogs extends Wxapp{
function __construct($inputs, $app_key){
parent::__construct($inputs, $app_key);
$this->login_white = array();//登录白名单
$this->check_status = array();//用户状态校验
$this->check_mobile = array();//需要手机号
$this->check_headimg =array();//授权微信信息
$this->load->model('receiver/receiver_customers_model','customers_model');
$this->load->model('receiver/receiver_customer_oplogs_model','customer_oplogs_model');
}
protected function get(){
$uid = $this->session['uid'];
$id = $this->input_param('id');
$page = $this->input_param('page');
$size = $this->input_param('size');
!$page && $page = 1;
!$size && $size = 20;
$where = [
'uid' => $uid,
'customer_id' => $id
];
$count = $this->customer_oplogs_model->count($where);
$lists = [];
if($count){
$rows = $this->customer_oplogs_model->select($where,'id desc',$page,$size,'log,type,c_time');
foreach($rows as $key => $val){
$lists[] = [
'content' => $val['log'],
'c_time' => date('Y.m.d',$val['c_time'])
];
}
}
$data = [
'list' => $lists,
'total' => $count
];
if($page == 1){ //获取统计数据
$row = $this->customers_model->get(['id'=>$id,'admin_id'=>$uid]);
$statistics = [
[
'name' => '去电',
'val' => $this->customer_oplogs_model->count(['customer_id'=>$id,'type'=>2]),
'color' => '#f3f6fc',
],
[
'name' => '短信',
'val' => $this->customer_oplogs_model->count(['customer_id'=>$id,'type'=>1]),
'color' => '#fffaeb',
],
[
'name' => '到店',
'val' => $row['a_num'],
'color' => '#f1f9f8',
],
[
'name' => '试驾',
'val' => $row['t_num'],
'color' => '#fff6f8',
]
];
$data['statistics'] = $statistics;
}
return $data;
}
}
+264 -12
View File
@@ -4,7 +4,7 @@ defined('WXAPP_APP') OR exit('No direct script access allowed');
/**
* Created by Vim
* User: lcc
* Date: 2020/06/23
* Date: 2021/06/23
* Time: 14:08
*/
require_once APPPATH.'controllers/wxapp/Wxapp.php';
@@ -13,17 +13,241 @@ class Customers extends Wxapp{
function __construct($inputs, $app_key){
parent::__construct($inputs, $app_key);
$this->login_white = 'all';//登录白名单
$this->login_white = array();//登录白名单
$this->check_status = array();//用户状态校验
$this->check_mobile = array();//需要手机号
$this->check_headimg =array();//授权微信信息
$this->load->model('receiver/receiver_customers_model','customers_model');
$this->load->model('receiver/receiver_customer_oplogs_model','customer_oplogs_model');
$this->load->model('auto/auto_series_model');
$this->load->model('auto/auto_brand_model');
}
protected function get(){
$id = $this->input_param('id');
if($id){
$where = [
'id' => $id,
];
$row = $this->customers_model->get($where);
if(!$row){
throw new Exception('数据不存在', ERR_PARAMS_ERROR);
}
$admin = $this->app_user_model->get(['id'=>$row['admin_id']],'id,uname');
$brand = $this->auto_brand_model->get(['id'=>$row['brand_id']],'name');
$series = $this->auto_series_model->get(['id'=>$row['s_id']],'name');
$car_json = json_decode($row['car_json'],true);
$color = isset($car_json['color']) ? $car_json['color']['title'] : '';
$version = isset($car_json['version']) ? $car_json['version']['title'] : '';
$tags = [$row['level'].'级用户'];
$status_name = $this->customers_model->get_status();
$tip = $status_name[$row['status']] ? $status_name[$row['status']] : '';
$other_data = [
'品牌车型' => $brand['name'].$series['name'],
'颜色型号' => $color.'-'.$version,
'建卡时间' => date('Y-m-d',$row['c_time']),
//'上次联系' => date('Y-m-d'),
'客户来源' => $row['cf_title'],
'销售顾问' => isset($admin) ? $admin['uname'] : '',
];
$data = [
'id' => $row['id'],
'name' => $row['name'],
'mobile' => '****'.substr($row['mobile'],-4),
'tip' => $tip,
'is_top' => $row['is_top'],
'status' => $row['status'],
'other_data' => $other_data,
'tags' => $tags
];
return $data;
}else{
return $this->lists();
}
}
//获取客户其它信息
protected function get_data(){
$id = $this->input_param('id');
$where = [
'id' => $id
];
$row = $this->customers_model->get($where);
if(!$row){
throw new Exception('数据不存在', ERR_PARAMS_ERROR);
}
$data['baseinfo'] = [
'客户姓名' => $row['name'],
'客户电话' => mobile_asterisk($row['mobile']),
];
return $data;
}
//创建客户
protected function post(){
$this->load->model('auto/auto_series_model');
$this->load->model('auto/auto_attr_model');
$name = $this->input_param('name');
$mobile = $this->input_param('mobile');
$car_id = $this->input_param('car_id'); //品牌车型id
$v_id = $this->input_param('v_id'); //车型id
$color_id = $this->input_param('color_id'); //颜色id
$back_s_id = $this->input_param('b_s_id'); //备选车型
$buy_time = $this->input_param('buy_time'); //预计购车时间
if(!mobile_valid($mobile)) throw new Exception('请输入正确的手机号码', ERR_PARAMS_ERROR);
if(!$name || !$car_id || !$v_id || !$color_id){
throw new Exception('参数错误', ERR_PARAMS_ERROR);
}
$row = $this->auto_series_model->get(['id'=>$car_id]);
$where = [
"id in ($v_id,$color_id)" => null
];
$attr_row = $this->auto_attr_model->map('id','',$where);
if($attr_row[$color_id]){
$color_row = $attr_row[$color_id][0];
$color_row['jsondata'] = json_decode($color_row['jsondata'],true);
}
if($attr_row[$v_id]){
$version_row = $attr_row[$v_id][0];
$version_row['jsondata'] = json_decode($version_row['jsondata'],true);
}
$car_json = [
'c_id' => $color_id,
'v_id' => $v_id,
'back_s_id' => $back_s_id,
'color' => isset($color_row) ? $color_row : '',
'version' => isset($version_row) ? $version_row : ''
];
$this->load->library('receiver/customers_entity');
$level = $this->customers_entity->cal_level(strtotime($buy_time),time());
$add_data = [
'name' => $name,
'mobile' => $mobile,
'brand_id' => $row['brand_id'],
's_id' => $row['id'],
'v_id' => $v_id,
'admin_id' => $this->session['uid'],
'level' => $level,
'cf_title' => '自行到店',
'car_json' => json_encode($car_json,JSON_UNESCAPED_UNICODE),
'c_time' => time()
];
$buy_time && $add_data['buy_time'] = date('Y-m-d H:i:s',strtotime($buy_time));
$result = $this->customers_model->add($add_data);
if($result){
throw new Exception('创建成功', API_CODE_SUCCESS);
}else{
throw new Exception('创建失败', ERR_PARAMS_ERROR);
}
}
//修改客户
protected function put(){
$uid = $this->session['uid'];
$id = $this->input_param('id');
$status = $this->input_param('status');
$t_num = $this->input_param('t_num');
$a_num = $this->input_param('a_num');
$is_top = $this->input_param('is_top');
$row = $this->customers_model->get(['id'=>$id,'admin_id'=>$uid]);
if(!$row){
throw new Exception('数据不存在', ERR_PARAMS_ERROR);
}
$up_data = [];
strlen($status) && $up_data['status'] = $status;
strlen($is_top) && $up_data['is_top'] = $is_top;
$t_num && $up_data['t_num = t_num+1'] = null;
$a_num && $up_data['a_num = a_num+1'] = null;
$result = true;
if($up_data){
$result = $this->customers_model->update($up_data,['id'=>$id]);
if($result){ //添加日志
$this->load->library('receiver/customers_entity');
$log = '';
if(strlen($status)){ //变更状态
$status_name = $this->customers_model->get_status();
$log .= '状态变更为'.$status_name[$status];
}
if($t_num){
$msg = '试驾+1';
$log = $log ? $log.','.$msg : $msg;
}
if($a_num){
$msg = '到店+1';
$log = $log ? $log.','.$msg : $msg;
}
$this->customers_entity->add_log($id,$uid,$this->session['uname'],$log);
}
}
if($result){
throw new Exception('修改成功', API_CODE_SUCCESS);
}else{
throw new Exception('修改失败', ERR_PARAMS_ERROR);
}
}
//订单列表头部
protected function get_tabs(){
$rows = $this->customers_model->get_status();
$lists = [];
if($rows){
foreach($rows as $key=>$val){
if($key!=-1){
$lists[] = [
'key' => $key,
'name' => $val
];
}
}
}
return $lists;
}
//获取筛选条件
protected function get_filter(){
$this->load->library('receiver/customers_entity');
$level = $this->customers_entity->get_level();
$cfrom = ['自行到店','后台分配'];
$data = [
'level' => $level,
'cfrom' => $cfrom
];
return $data;
}
//获取客户列表
private function lists(){
$uid = $this->session['uid'];
$group_id = $this->session['group_id'];
$s_time = $this->input_param('s_time');
$e_time = $this->input_param('e_time');
$if_driver = $this->input_param('if_driver');
$level = $this->input_param('level');
$s_id = $this->input_param('s_id'); //车系id
$v_id = $this->input_param('v_id'); //车型级别id
$cfrom = $this->input_param('cfrom'); //客户来源id
$status = $this->input_param('status'); //状态
$o_type = $this->input_param('o_type'); //排序
$page = $this->input_param('page');
$size = $this->input_param('size');
!$page && $page = 1;
!$size && $size = 10;
if($o_type==1){ //创建时间排序
$orderby = 'c_time desc';
}elseif($o_type==2){//最近联系
$orderby = 'cont_time desc';
}else{ //特别关注
$orderby = 'is_top desc,id desc';
}
if($group_id==3){ //掌柜
$where = [];
}elseif($group_id==2){ //店长
@@ -39,11 +263,20 @@ class Customers extends Wxapp{
'admin_id' => $uid
];
}
if($s_time && $e_time){
$where['c_time >='] = strtotime($s_time);
$where['c_time <='] = strtotime(date('Y-m-d 23:59:59',strtotime($e_time)));
}
strlen($if_driver) && $where['if_driver'] = 1;
strlen($status) && $where['status'] = $status;
$level && $where['level'] = $level;
$cfrom && $where['cf_title'] = $cfrom;
$count = $this->customers_model->count($where);
$lists = [];
if($count){
$fileds = 'id,name,admin_id,mobile,car_json,is_top,cf_id,c_time';
$rows = $this->customers_model->select($where,'is_top desc,id desc',$page,$size,$fileds);
$fileds = 'id,name,admin_id,mobile,level,car_json,is_top,cf_title,brand_id,s_id,c_time';
$rows = $this->customers_model->select($where,$orderby,$page,$size,$fileds);
//获取管理员
$admin_arr = array_unique(array_column($rows,'admin_id'));
$admin_ids = implode(',',$admin_arr);
@@ -54,28 +287,48 @@ class Customers extends Wxapp{
];
$admins = $this->app_user_model->map('id','',$where,'','','','id,uname');
}
//获取来源
$cf_arr = array_unique(array_column($rows,'cf_id'));
//品牌车型
$brand_arr = array_unique(array_column($rows,'brand_id'));
$brand_ids = implode(',',$brand_arr);
if($brand_ids){
$where = [
"id in ({$brand_ids})" => null
];
$brands = $this->auto_brand_model->map('id','',$where,'','','','id,name');
}
//车系车型
$series_arr = array_unique(array_column($rows,'s_id'));
$series_ids = implode(',',$series_arr);
if($series_ids){
$where = [
"id in ({$series_ids})" => null
];
$series = $this->auto_series_model->map('id','',$where,'','','','id,name');
}
foreach($rows as $key => $val){
$car_json = json_decode($val['car_json'],true);
$color = isset($car_json['color']) ? $car_json['color']['title'] : '';
$version = isset($car_json['version']) ? $car_json['version']['title'] : '';
$cfrom = '';;
$brand_name = isset($brands[$val['brand_id']]) ? $brands[$val['brand_id']][0]['name'] : '';
$serie_name = isset($series[$val['s_id']]) ? $series[$val['s_id']][0]['name'] : '';
$other_data = [
'品牌车型' => '东风EX1',
'品牌车型' => $brand_name.$serie_name,
'颜色型号' => $color.'-'.$version,
'建卡时间' => date('Y-m-d',$val['c_time']),
'上次联系' => date('Y-m-d'),
'客户来源' => $cfrom,
//'上次联系' => date('Y-m-d'),
'客户来源' => $val['cf_title'],
'销售顾问' => isset($admins[$val['admin_id']]) ? $admins[$val['admin_id']][0]['uname'] : '',
];
$tags = [$val['level'].'级用户'];
$lists[] = [
'id' => $val['id'],
'name' => $val['name'],
'mobile' => mobile_asterisk($val['mobile']),
'is_top' => $val['is_top'],
'other_data' => $other_data
'other_data' => $other_data,
'tags' => $tags
];
}
}
@@ -85,5 +338,4 @@ class Customers extends Wxapp{
];
return $data;
}
}
+105
View File
@@ -0,0 +1,105 @@
<?php
defined('WXAPP_APP') OR exit('No direct script access allowed');
/**
* Created by Vim
* User: lcc
* Date: 2021/06/23
* Time: 14:08
*/
require_once APPPATH.'controllers/wxapp/Wxapp.php';
class Employees extends Wxapp{
function __construct($inputs, $app_key){
parent::__construct($inputs, $app_key);
$this->login_white = array();//登录白名单
$this->check_status = array();//用户状态校验
$this->check_mobile = array();//需要手机号
$this->check_headimg =array();//授权微信信息
}
public function get(){
$where = [
'pid' => $this->session['uid'],
'status>-1' => null
];
$count = $this->app_user_model->count($where);
$lists = [];
if($count){
$fileds = 'id,uname,mobile,status';
$rows = $this->app_user_model->select($where,'id desc',$page,$size,$fileds);
$lists = $rows;
}
$data = [
'list' => $lists,
'total' => $count
];
return $data;
}
protected function post(){
$group_id = $this->session['group_id'];
$name = $this->input_param('name');
$mobile = $this->input_param('mobile');
if($group_id!=2){
throw new Exception('无法添加店员', ERR_PARAMS_ERROR);
}
if(!mobile_valid($mobile)||!$name){
throw new Exception('请输入正确手机号和姓名', ERR_PARAMS_ERROR);
}
$row = $this->app_user_model->get(['mobile'=>$mobile,'status>=0'=>null]);
if($row){
throw new Exception('手机号已存在', ERR_PARAMS_ERROR);
}
$data = [
'pid' => $this->session['uid'],
'mobile' => $mobile,
'uname' => $name,
'group_id' => 1,
'c_time' => time()
];
$result = $this->app_user_model->add($data);
if($result){
throw new Exception('创建成功', API_CODE_SUCCESS);
}else{
throw new Exception('创建失败', ERR_PARAMS_ERROR);
}
}
protected function put(){
$id = $this->input_param('id');
$status = $this->input_param('status');
$where = [
'pid' => $this->session['uid'],
'id' => $id
];
$row = $this->app_user_model->get($where);
if(!$row){
throw new Exception('用户不存在', ERR_PARAMS_ERROR);
}
$update = [];
if(strlen($status)){
$update['status'] = $status ? 1 : 0;
}
$this->app_user_model->update($update,$where);
throw new Exception('更新成功', API_CODE_SUCCESS);
}
protected function delete(){
$id = $this->input_param('id');
$where = [
'pid' => $this->session['uid'],
'id' => $id
];
$row = $this->app_user_model->get($where);
if(!$row){
throw new Exception('用户不存在', ERR_PARAMS_ERROR);
}
$this->app_user_model->update(['status'=>-1],$where);
throw new Exception('删除成功', API_CODE_SUCCESS);
}
}
+34
View File
@@ -0,0 +1,34 @@
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Created by Vim
* User: lcc
* Date: 2021/07/13
* Time: 14:08
*/
class Loan extends CI_Controller{
public function __construct($inputs, $app_key){
parent::__construct($inputs, $app_key);
$this->login_white = array();//登录白名单
$this->check_status = array();//用户状态校验
$this->check_mobile = array();//需要手机号
$this->check_headimg =array();//授权微信信息
}
public function get(){
$banks = [
'中国农行'
];
$years = [
1,2,3,4,5
];
$data = [
'banks' => $banks,
'years' => $years
];
return $data;
}
}
+94
View File
@@ -0,0 +1,94 @@
<?php
defined('BASEPATH') OR exit('No direct script access allowed');
/**
* Created by Vim
* User: lcc
* Date: 2021/07/07
* Time: 14:08
*/
class Protocol extends CI_Controller{
public function __construct($inputs, $app_key){
parent::__construct($inputs, $app_key);
$this->load->model('receiver/order/receiver_orders_model','orders_model');
$this->load->model('receiver/order/receiver_order_contracts_model','contracts_model');
$this->load->model('auto/auto_series_model');
$this->load->model('auto/auto_brand_model');
}
//整车合同
public function car(){
$wxapp = $this->input->get('wxapp');
$id = $this->input->get('id');
$row = $this->orders_model->get(['id'=>$id]);
$contract = $this->contracts_model->get(['o_id'=>$id,'type'=>0]);
if($row){
$brand = $this->auto_brand_model->get(['id'=>$row['brand_id']],'name');
$series = $this->auto_series_model->get(['id'=>$row['s_id']],'name');
$car_json = json_decode($row['car_json'],true);
$color = isset($car_json['color']) ? $car_json['color']['title'] : '';
$version = isset($car_json['version']) ? $car_json['version']['title'] : '';
$row['brand_name'] = $brand['name'].$series['name'].' '.$version;
$row['color'] = $color;
}
$row['day'] = $contract ? date('Y年m月d日',$contract['c_time']):date('Y年m月d日');
$row['price_rmb'] = num_to_rmb($row['price']);
$row['cid'] = $contract['cid'];
$folder = $wxapp ? 'protocol' : 'pdf2img';
$this->load->view("wxapp/licheb/{$folder}/car",$row);
}
//代理合同
public function agent(){
$wxapp = $this->input->get('wxapp');
$id = $this->input->get('id');
$row = $this->orders_model->get(['id'=>$id]);
$contract = $this->contracts_model->get(['o_id'=>$id,'type'=>1]);
$row['day'] = $contract ? date('Y年m月d日',$contract['c_time']):date('Y年m月d日');
$row['cid'] = $contract['cid'];
$folder = $wxapp ? 'protocol' : 'pdf2img';
$this->load->view("wxapp/licheb/{$folder}/agent",$row);
}
//车辆信息确认单
public function car_ck(){
$wxapp = $this->input->get('wxapp');
$this->load->model('receiver/order/receiver_order_ckcars_model','ckcars_model');
$id = $this->input->get('id');
$row = $this->orders_model->get(['id'=>$id]);
if($row){
$brand = $this->auto_brand_model->get(['id'=>$row['brand_id']],'name');
$series = $this->auto_series_model->get(['id'=>$row['s_id']],'name');
$car_json = json_decode($row['car_json'],true);
$version = isset($car_json['version']) ? $car_json['version']['title'] : '';
$row['brand_name'] = $brand['name'].$series['name'].' '.$version;
}
$contract = $this->contracts_model->get(['o_id'=>$id,'type'=>2]);
$ck_row = $this->ckcars_model->get(['o_id'=>$id],'vin');
$row['day'] = $contract ? date('Y年m月d日',$contract['c_time']):date('Y年m月d日');
$row['cid'] = $contract['cid'];
$row['vin'] = $ck_row['vin'];
$folder = $wxapp ? 'protocol' : 'pdf2img';
$this->load->view("wxapp/licheb/{$folder}/car_ck",$row);
}
//车辆交接信息
public function car_fh(){
$wxapp = $this->input->get('wxapp');
$id = $this->input->get('id');
$row = $this->orders_model->get(['id'=>$id]);
$contract = $this->contracts_model->get(['o_id'=>$id,'type'=>3]);
if($row){
$brand = $this->auto_brand_model->get(['id'=>$row['brand_id']],'name');
$series = $this->auto_series_model->get(['id'=>$row['s_id']],'name');
$car_json = json_decode($row['car_json'],true);
$color = isset($car_json['color']) ? $car_json['color']['title'] : '';
$version = isset($car_json['version']) ? $car_json['version']['title'] : '';
$row['brand_name'] = $brand['name'].$series['name'].' '.$version;
$row['color'] = $color;
}
$row['day'] = $contract ? date('Y年m月d日',$contract['c_time']):date('Y年m月d日');
$row['cid'] = $contract['cid'];
$folder = $wxapp ? 'protocol' : 'pdf2img';
$this->load->view("wxapp/licheb/{$folder}/car_fh",$row);
}
}
+24 -4
View File
@@ -4,7 +4,7 @@ defined('WXAPP_APP') OR exit('No direct script access allowed');
/**
* Created by Vim
* User: lcc
* Date: 2020/06/23
* Date: 2021/06/23
* Time: 14:08
*/
require_once APPPATH.'controllers/wxapp/Wxapp.php';
@@ -40,10 +40,30 @@ class Sms extends Wxapp{
$code = random_string('numeric', 6);
$mc->save($key, $code, 600);
}
//send_sms($mobile,$code);
//$msg = '发送成功';
$msg = $code;
send_sms($mobile,$code);
$msg = '发送成功';
//$msg = $code;
throw new Exception($msg, API_CODE_SUCCESS);
}
//发短信给客户
protected function post_customer(){
$this->load->model('receiver/receiver_customers_model','customers_model');
$uid = $this->session['uid'];
$id = $this->input_param('id');
$content = $this->input_param('content');
$row = $this->customers_model->get(['id'=>$id,'admin_id'=>$uid]);
if(!$row || !$content){
throw new Exception('参数错误', ERR_PARAMS_ERROR);
}
$mobile = $row['mobile'];
$content = '【狸车】'.$content;
b2m_send_sms($mobile,$content);
$this->load->library('receiver/customers_entity');
$log = '发送短信+1';
$this->customers_entity->add_log($id,$uid,$this->session['uname'],$log,1);
throw new Exception('短信发送成功', API_CODE_SUCCESS);
}
}
+6 -2
View File
@@ -4,7 +4,7 @@ defined('WXAPP_APP') OR exit('No direct script access allowed');
/**
* Created by Vim
* User: lcc
* Date: 2020.06.23
* Date: 2021.06.23
* Time: 14:08
*/
require_once APPPATH.'controllers/wxapp/Wxapp.php';
@@ -45,6 +45,9 @@ class User extends Wxapp{
if(!$user){
throw new Exception('用户不存在', API_CODE_FAIL);
}
if(!$user['status']){
throw new Exception('该账号已停用', API_CODE_FAIL);
}
$session = $this->wx_session($code);
//print_r($session);
if(!$session['session_key']){
@@ -82,7 +85,8 @@ class User extends Wxapp{
$data = array(
'uid' => $uid,
'uname' => $user['uname'],
'mobile' => $user['mobile']
'mobile' => $user['mobile'],
'group_id' => $user['group_id']
);
return $data;
-22
View File
@@ -1,22 +0,0 @@
<html>
<script>
//ws://192.168.0.16:9501?platform=home&uid=用户id&app_id=应用id {platform:['home','api','biz','admin']}
var wsServer = 'ws://<?=$ip?>:<?=$port?>?platform=home&uid=333';
var websocket = new WebSocket(wsServer);
websocket.onopen = function (evt) {
console.log("Connected to WebSocket server.");
};
websocket.onclose = function (evt) {
console.log("Disconnected");
};
websocket.onmessage = function (evt) {
console.log('Retrieved data from server: ' + evt.data);
};
websocket.onerror = function (evt, e) {
console.log('Error occured: ' + evt.data);
};
</script>
</html>
+67
View File
@@ -0,0 +1,67 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>委托代理服务协议</title>
</head>
<body>
<style>
html,body,div,span,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,code,del,dfn,em,img,q,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border-style:none;}
html,body,div,span,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,code,del,dfn,em,img,q,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,textarea,input[type="text"]{font-size:100%;vertical-align:baseline;}
input{border:none;padding:0;margin:0;}
body{font:normal normal normal 12px/1.6 normal;color:#333;}
article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}
audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}
audio:not([controls]){display:none;}[hidden]{display:none;}
*{-webkit-text-size-adjust:none;}
*:focus{outline:none;}
a{color:#333;text-decoration:none;}
a:focus,input:focus{-moz-outline-style:none;outline-style:none;}
a:hover{text-decoration:none;}
li{list-style:none; font-size:16px; text-align: center; font-weight: bold;}
.fn-clear:before,.fn-clear:after{content:"";display:table;}
.fn-clear:after{clear:both;}
.fn-clear{zoom:1;}
.fn-fl{float:left;}
.fn-fr{float:right;}
.wp45{width:45%;}
</style>
<div style="font-size:14px;">
<div style="text-align:center;font-weight:bold;font-size:16px;">委托代理服务协议</div>
<div style="">甲方(出卖人):厦门狸车科技有限公司</div>
<div style="">乙方(买受人):<?=$name?></div>
<div style="">乙方为节省时间和精力,自愿委托甲方办理品牌为东风EX1的车辆下列委托事项,并达成如下协议:</div>
<div style="">一、委托事项、委托事项所需费用概算及代办费约定(乙方授权甲方代办下列事项打√,单位:元)</div>
<p>1、车辆保险:</p>
<p>相关说明:保费由乙方支付给保险公司;</p>
<p>二、代办上牌、按揭手续等;</p>
<p>三、费用结算:办理上述委托事项有关手续的各项费用均由乙方承担,乙方预付委托事项所需的费用,结算时凭相关票据多退少补。预付费用: 元。</p>
<p>四、双方特别约定:</p>
<p>1、上牌服务自乙方付清挂牌等费用之日起个 工作日内完成;</p>
<p>2、车牌选号若为代选号牌时,均由甲方电话通知乙方,因乙方未能及时选号等其它原因,甲方有权代理决定并不对最终选号结果负责;若为自选号牌,甲方可配合乙方上牌,但不对最终选号结果负责。</p>
<p>3、乙方委托甲方办理本协议第一条第二款服务的,乙方应事先办妥机动车车辆保险,投保险种包括但不限于车辆损失险和第三者责任险。保险合同应当书面约定以下内容:“发生保险事故时,若车辆未取得公安交通管理部门核发的行驶证和号牌,保险公司不得免除赔偿责任”。甲方在代办服务过程中造成车辆毁损、灭失的,乙方应当先向保险公司索赔,赔付不足部分由甲方予以修复或赔偿。</p>
<p>4、乙方委托甲方办理本协议第一条第一款服务的,如车辆发生毁损、灭失的,除甲方原因外,代办保险中双方特别约定内容未能及时全面落实的,应当免除甲方的责任。保险条款及费用以保险公司合同为准。</p>
<p>5、委托人已阅读全部材料,充分了解并清楚委托的风险及甲方接受委托提供服务的付出及收取的服务费用合理,自愿遵守本委托的各项规则,且本委托为不可撤销之委托。</p>
<p>6、因本协议产生的纠纷,双方应协商解决;协商不成的,任何一方可向甲方所在地人民法院起诉。</p>
<p>7、本协议自甲、乙双方签字或盖章之日起生效。</p>
<div style="margin-top:50px;">
<table style="width:100%;">
<tr>
<td style="width:60%;">
<div>甲方(盖章)</div>
<div>日期:<?=$day?></div>
</td>
<td style="width:40%;">
<div>乙方(盖章)</div>
<div>日期:<?=$day?></div>
</td>
</tr>
</table>
</div>
</div>
</body>
</html>
+97
View File
@@ -0,0 +1,97 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>车辆整车合同</title>
</head>
<body>
<div style="font-size:14px;">
<div style="text-align:center;font-weight:bold;font-size:16px;">车辆整车合同</div>
<div style="text-align:right;">合同编号:<?=$cid?></div>
<div>甲方(出卖人):厦门狸车科技有限公司</div>
<div>统一社会信用代码:JJSD992323KK2333</div>
<div>联系电话:180XXXXXXXX</div>
<div>甲、乙双方依据《中华人民共和国合同法》及其他有关法律、法规的规定,在平等、自愿、协商一致的基础上,就买卖汽车事宜,订立本合同。</div>
<div>第一条 车辆基本情况</div>
<div>
<table style="width:100%;">
<tr>
<td style="width:50%;">
车辆品牌:<?=$brand_name?>
</td>
<td style="width:50%;">
颜色:<?=$color?>
</td>
</tr>
</table>
</div>
<div>第二条 价款与数量</div>
<div>
<table style="width:100%;">
<tr>
<td style="width:50%;">
车辆单价:<?=number_format($price,2)?> 元
</td>
<td style="width:50%;">
数量:1
</td>
</tr>
<tr>
<td style="width:50%;">
车辆总价:<?=number_format($price,2)?> 元
</td> <td style="width:50%;">
<?=$price_rmb?>
</td>
</tr>
</table>
</div>
<div>车辆单价为车身单价,不包含车辆购置税、车辆保险费、挂牌杂费等其他费用。乙方如需委托甲方代理上牌、委托运输等服务的,双方应另外签订《委托服务协议》。</div>
<div>第三条 付款方式及期限</div>
<div>乙方选择下述第 种方式付款:</div>
<div>1、定金支付方式:乙方在签订合同时即付定金人民币: 元,定金</div>
<div>2、一次性付款方式:支付全部车价款,计人民币 元。</div>
<div>第七条 车辆验收</div>
<div>1、甲方向乙方交付汽车及随车文件时应当场验收。乙方应对所购车辆进行认真检查、确认。如有异议,应当场提出。验收完毕,双方需签署《新车交付表》(附件),即为该车辆正式交付。乙方委托运输方代为提车的,甲方与运输方签署《新车交付表》即为该车辆正式交付。</div>
<div>第八条 质量、维修、更换、退车</div>
<div>1、甲方向乙方出售的车辆,应当不存在危及人身、财产安全的不合理的危险,符合保障人体健康和人身、财产安全的国家标准、行业标准,具备产品应当具备的使用性能等,符合注明采用的产品标准,符合以产品、实物样品等方式表明的质量状况。符合出厂检验标准,符合安全驾驶和说明书载明的使用要求。双方另有约定的情形除外。</div>
<div>2、甲方向乙方出售的车辆,必须是经国家有关部门公布、备案的汽车产品公告上的产品或合法进口的产品,并符合公安交通管理部门关于机动车辆的注册登记条件。 </div>
<div>3、甲方保证向乙方出售的车辆,在交付前已作必要的检查和清洁,并按生产厂的技术要求完成交车前检查(PDI/PDS)并排除已发现的汽车故障或瑕疵。 </div>
<div>4、甲方向乙方出售的车辆,按照生产厂承诺的内容维修、保养。(1)甲方向乙方出售的车辆的包修期限,为叁年或者行驶里程壹拾万公里,以先到者为准;三包有效期(如适用),为两年或者行驶里程伍万公里,以先到者为准。  (2)其他约定:以上年限和公里数以乙方购买车辆对应的《质量担保和保养手册》记载的公里数和年限为准。  </div>
<div>5、生产厂(或甲方)指导特约维修站(地址 :                 联系电话 :               )提供缺陷汽车产品召回、汽车质 量“三包”等售后服务,其他售后服务网点可向甲方查询。 </div>
<div>6、乙方使用车辆前应仔细阅读说明书、用户使用手册或保修手册、保养手册等相关资料。如由于未按照使用说明书要求正确使用、维护、保养、修理车辆,或自行改装、调整、拆卸,或未按生产厂技术要求使用合格的工作油液及滤清器,以及其因他不当行为致使车辆出现故障的,由乙方自行承担责任。 </div>
<div>7、乙方所购汽车如在保修期内出现质量问题,甲方(生产厂)应明确承担维修任务的维修站(厂)负责免费维修。</div>
<div>8、以上条款未尽事宜,按照国家有关汽车产品修理、更换、退货的规定、机动车维修管理规定和生产厂的有关汽车产品修理、更换、退货的规定和操作流程执行。</div>
<div>9、乙方所购车辆如属生产厂公布的汽车召回范围,甲方应当召回。</div>
<div>第九条 不可抗力</div>
<div>任何一方因不可抗力的原因,致使车辆不能交接或逾期交接的,可免除违约责任。遇有不可抗力的一方,应负有及时通知并在10日内提供不能履行合同的书面证明。</div>
<div>第十条 违约责任</div>
<div>除本同第七条规定的特殊情况外:</div>
<div>1、若甲方逾期交车,自逾期之日起至实际交付之日,甲方按日向乙方支付车价款万分之伍的违约金,合同继续履行,逾期超过陆拾天,乙方有权解除合同。合同解除后,甲方应当自乙方解除合同之日起陆拾日内退还已付款。</div>
<div>2、若乙方逾期付款,自逾期之日起至实际支付之日,乙方按日向甲方支付车价款万分之伍的违约金,合同继续履行,逾期超过陆拾天,甲方有权解除合同。</div>
<div>3、经甲乙双方约定的或有关行政部门依法认定的汽车检验机构鉴定乙方所购汽车存在设计、制造缺陷,造成的人身、财产损害的,甲方应依法承担责任。</div>
<div>第十一条 争议的解决方式</div>
<div>甲、乙双方在履行本合同过程中发生争议,应协商解决,也可请求消费者协会或其他机构调解。协商不能解决或调解不成的,依法向甲方所在地人民法院起诉。</div>
<div>第十二条 其他</div>
<div>1、双方应保证在合同中填写的姓名、地址、电话等内容真实有效,若有改变,应及时书面通知对方,否则由此造成的损失及相关责任由变更方负责。本合同约定的联系地址和联系方式,亦可作为司法送达的法定地址。</div>
<div>2、本合同的未尽事宜及本合同在履行过程中需变更的事宜,双方可通过订立补充条款或补充协议进行约定。补充条款、补充协议及附件均为不可分割的部分。  </div>
<div>3、本合同及其补充条款、补充协议及附件中的手写文字与打印文字有矛盾时,以手写文字为准。如阿拉伯数字与大写数字有矛盾时,以大写数字为准。  </div>
<div>4、本合同自双方签字或盖章之日起生效,本合同壹式叁份,具有同等效力</div>
<div style="margin-top:50px;">
<table style="width:100%;">
<tr>
<td style="width:60%;">
<div>甲方(盖章)</div>
<div>日期:<?=$day?></div>
</td>
<td style="width:40%;">
<div>乙方(盖章)</div>
<div>日期:<?=$day?></div>
</td>
</tr>
</table>
</div>
</div>
</body>
</html>
@@ -0,0 +1,31 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>车辆信息确认单</title>
</head>
<body>
<div style="font-size:14px;">
<div style="text-align:center;font-weight:bold;font-size:16px;">车辆信息确认单</div>
<div>甲方(出卖人):厦门狸车科技有限公司</div>
<div>乙方(买受人):<?=$name?></div>
<div>乙方于<?=date('Y年m月d日',$c_time)?>在甲方购买 <?=$brand_name?> 车辆 1 台,并确认车架号为:<?=$vin?>。乙方已对上述车辆的厂牌型号、配置等进行认真检查并验收合格无异议。</div>
<div style="margin-top:50px;">
<table style="width:100%;">
<tr>
<td style="width:60%;">
<div>甲方(盖章)</div>
<div>日期:<?=$day?></div>
</td>
<td style="width:40%;">
<div>乙方(盖章)</div>
<div>日期:<?=$day?></div>
</td>
</tr>
</table>
</div>
</div>
</body>
</html>
+133
View File
@@ -0,0 +1,133 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>车辆信息确认单</title>
</head>
<body>
<div style="font-size:14px;">
<div style="text-align:center;font-weight:bold;font-size:16px;">车辆信息确认单</div>
<div style="text-align:right;">合同编号:<?=$cid?></div>
<div>甲方(出卖人):厦门狸车科技有限公司</div>
<div>乙方(买受人):<?=$name?></div>
<div>
<table style="width:100%;">
<tr>
<td style="width:50%;">
身份证:350XXXXXXXXXXXXX
</td>
<td style="width:50%;">
联系电话:<?=$mobile?>
</td>
</tr>
</table>
</div>
<div>一、车辆信息</div>
<div>
<table style="width:100%;">
<tr>
<td style="width:50%;">
车辆品牌:<?=$brand_name?>
</td>
<td style="width:50%;">
颜色:<?=$color?>
</td>
</tr>
<tr>
<td style="width:50%;">
车身号:
</td>
<td style="width:50%;">
车牌号:
</td>
</tr>
</table>
</div>
<div>二、车辆结算信息</div>
<div>
<table style="width:100%;">
<tr>
<td style="width:50%;">
合同售价:<?=number_format($price,2)?> 元
</td>
<td style="width:50%;">
付款方式:<?=$payway?'全款':'分期'?>
</td>
</tr>
<?if(!$payway){?>
<tr>
<td style="width:50%;">
按揭银行:农业银行
</td>
<td style="width:50%;">
贷款期数:36
</td>
</tr>
<?}?>
</table>
</div>
<div>三、代理款信息</div>
<div>
<table style="width:100%;">
<tr>
<td style="width:50%;">
购置税 :
</td>
<td style="width:50%;">
保险:
</td>
</tr>
<tr>
<td style="width:50%;">
保险风险金:
</td>
<td style="width:50%;">
代收利息:
</td>
</tr>
<tr>
<td style="width:50%;">
上牌服务费:
</td>
<td style="width:50%;">
抵押解押服务费:
</td>
</tr>
<tr>
<td style="width:50%;" colspan="2">
新车安全服务包:
</td>
</tr>
</table>
</div>
<div>四、新车交付信息</div>
<div>
<table style="width:100%;">
<tr>
<td style="width:50%;">
整车钥匙两把
</td>
<td style="width:50%;">
车辆登记证
</td>
</tr>
<tr>
<td style="width:50%;">
机动车定期检验合格证
</td>
<td style="width:50%;">
保养协议
</td>
</tr>
</table>
</div>
<div style="margin-top:50px;">
<div>销售顾问:</div>
<div>日期:<?=$day?></div>
</div>
</div>
</body>
</html>
+67
View File
@@ -0,0 +1,67 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>委托代理服务协议</title>
</head>
<body>
<style>
html,body,div,span,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,code,del,dfn,em,img,q,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td{margin:0;padding:0;border-style:none;}
html,body,div,span,object,iframe,h1,h2,h3,h4,h5,h6,p,blockquote,pre,a,abbr,acronym,address,code,del,dfn,em,img,q,dl,dt,dd,ol,ul,li,fieldset,form,label,legend,table,caption,tbody,tfoot,thead,tr,th,td,textarea,input[type="text"]{font-size:100%;vertical-align:baseline;}
input{border:none;padding:0;margin:0;}
body{font:normal normal normal 12px/1.6 normal;color:#333;}
article,aside,details,figcaption,figure,footer,header,hgroup,nav,section{display:block;}
audio,canvas,video{display:inline-block;*display:inline;*zoom:1;}
audio:not([controls]){display:none;}[hidden]{display:none;}
*{-webkit-text-size-adjust:none;}
*:focus{outline:none;}
a{color:#333;text-decoration:none;}
a:focus,input:focus{-moz-outline-style:none;outline-style:none;}
a:hover{text-decoration:none;}
li{list-style:none; font-size:16px; text-align: center; font-weight: bold;}
.fn-clear:before,.fn-clear:after{content:"";display:table;}
.fn-clear:after{clear:both;}
.fn-clear{zoom:1;}
.fn-fl{float:left;}
.fn-fr{float:right;}
.wp45{width:45%;}
</style>
<div style="font-size:14px;">
<div style="text-align:center;font-weight:bold;font-size:16px;">委托代理服务协议</div>
<div style="">甲方(出卖人):厦门狸车科技有限公司</div>
<div style="">乙方(买受人):<?=$name?></div>
<div style="">乙方为节省时间和精力,自愿委托甲方办理品牌为东风EX1的车辆下列委托事项,并达成如下协议:</div>
<div style="">一、委托事项、委托事项所需费用概算及代办费约定(乙方授权甲方代办下列事项打√,单位:元)</div>
<p>1、车辆保险:</p>
<p>相关说明:保费由乙方支付给保险公司;</p>
<p>二、代办上牌、按揭手续等;</p>
<p>三、费用结算:办理上述委托事项有关手续的各项费用均由乙方承担,乙方预付委托事项所需的费用,结算时凭相关票据多退少补。预付费用: 元。</p>
<p>四、双方特别约定:</p>
<p>1、上牌服务自乙方付清挂牌等费用之日起个 工作日内完成;</p>
<p>2、车牌选号若为代选号牌时,均由甲方电话通知乙方,因乙方未能及时选号等其它原因,甲方有权代理决定并不对最终选号结果负责;若为自选号牌,甲方可配合乙方上牌,但不对最终选号结果负责。</p>
<p>3、乙方委托甲方办理本协议第一条第二款服务的,乙方应事先办妥机动车车辆保险,投保险种包括但不限于车辆损失险和第三者责任险。保险合同应当书面约定以下内容:“发生保险事故时,若车辆未取得公安交通管理部门核发的行驶证和号牌,保险公司不得免除赔偿责任”。甲方在代办服务过程中造成车辆毁损、灭失的,乙方应当先向保险公司索赔,赔付不足部分由甲方予以修复或赔偿。</p>
<p>4、乙方委托甲方办理本协议第一条第一款服务的,如车辆发生毁损、灭失的,除甲方原因外,代办保险中双方特别约定内容未能及时全面落实的,应当免除甲方的责任。保险条款及费用以保险公司合同为准。</p>
<p>5、委托人已阅读全部材料,充分了解并清楚委托的风险及甲方接受委托提供服务的付出及收取的服务费用合理,自愿遵守本委托的各项规则,且本委托为不可撤销之委托。</p>
<p>6、因本协议产生的纠纷,双方应协商解决;协商不成的,任何一方可向甲方所在地人民法院起诉。</p>
<p>7、本协议自甲、乙双方签字或盖章之日起生效。</p>
<div style="margin-top:50px;">
<table style="width:100%;">
<tr>
<td style="width:60%;">
<div>甲方(盖章)</div>
<div>日期:<?=$day?></div>
</td>
<td style="width:40%;">
<div>乙方(盖章)</div>
<div>日期:<?=$day?></div>
</td>
</tr>
</table>
</div>
</div>
</body>
</html>
+97
View File
@@ -0,0 +1,97 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>车辆整车合同</title>
</head>
<body>
<div style="font-size:14px;">
<div style="text-align:center;font-weight:bold;font-size:16px;">车辆整车合同</div>
<div style="text-align:right;">合同编号:<?=$cid?></div>
<div>甲方(出卖人):厦门狸车科技有限公司</div>
<div>统一社会信用代码:JJSD992323KK2333</div>
<div>联系电话:180XXXXXXXX</div>
<div>甲、乙双方依据《中华人民共和国合同法》及其他有关法律、法规的规定,在平等、自愿、协商一致的基础上,就买卖汽车事宜,订立本合同。</div>
<div>第一条 车辆基本情况</div>
<div>
<table style="width:100%;">
<tr>
<td style="width:50%;">
车辆品牌:<?=$brand_name?>
</td>
<td style="width:50%;">
颜色:<?=$color?>
</td>
</tr>
</table>
</div>
<div>第二条 价款与数量</div>
<div>
<table style="width:100%;">
<tr>
<td style="width:50%;">
车辆单价:<?=number_format($price,2)?> 元
</td>
<td style="width:50%;">
数量:1
</td>
</tr>
<tr>
<td style="width:50%;">
车辆总价:<?=number_format($price,2)?> 元
</td> <td style="width:50%;">
<?=$price_rmb?>
</td>
</tr>
</table>
</div>
<div>车辆单价为车身单价,不包含车辆购置税、车辆保险费、挂牌杂费等其他费用。乙方如需委托甲方代理上牌、委托运输等服务的,双方应另外签订《委托服务协议》。</div>
<div>第三条 付款方式及期限</div>
<div>乙方选择下述第 种方式付款:</div>
<div>1、定金支付方式:乙方在签订合同时即付定金人民币: 元,定金</div>
<div>2、一次性付款方式:支付全部车价款,计人民币 元。</div>
<div>第七条 车辆验收</div>
<div>1、甲方向乙方交付汽车及随车文件时应当场验收。乙方应对所购车辆进行认真检查、确认。如有异议,应当场提出。验收完毕,双方需签署《新车交付表》(附件),即为该车辆正式交付。乙方委托运输方代为提车的,甲方与运输方签署《新车交付表》即为该车辆正式交付。</div>
<div>第八条 质量、维修、更换、退车</div>
<div>1、甲方向乙方出售的车辆,应当不存在危及人身、财产安全的不合理的危险,符合保障人体健康和人身、财产安全的国家标准、行业标准,具备产品应当具备的使用性能等,符合注明采用的产品标准,符合以产品、实物样品等方式表明的质量状况。符合出厂检验标准,符合安全驾驶和说明书载明的使用要求。双方另有约定的情形除外。</div>
<div>2、甲方向乙方出售的车辆,必须是经国家有关部门公布、备案的汽车产品公告上的产品或合法进口的产品,并符合公安交通管理部门关于机动车辆的注册登记条件。 </div>
<div>3、甲方保证向乙方出售的车辆,在交付前已作必要的检查和清洁,并按生产厂的技术要求完成交车前检查(PDI/PDS)并排除已发现的汽车故障或瑕疵。 </div>
<div>4、甲方向乙方出售的车辆,按照生产厂承诺的内容维修、保养。(1)甲方向乙方出售的车辆的包修期限,为叁年或者行驶里程壹拾万公里,以先到者为准;三包有效期(如适用),为两年或者行驶里程伍万公里,以先到者为准。  (2)其他约定:以上年限和公里数以乙方购买车辆对应的《质量担保和保养手册》记载的公里数和年限为准。  </div>
<div>5、生产厂(或甲方)指导特约维修站(地址 :                 联系电话 :               )提供缺陷汽车产品召回、汽车质 量“三包”等售后服务,其他售后服务网点可向甲方查询。 </div>
<div>6、乙方使用车辆前应仔细阅读说明书、用户使用手册或保修手册、保养手册等相关资料。如由于未按照使用说明书要求正确使用、维护、保养、修理车辆,或自行改装、调整、拆卸,或未按生产厂技术要求使用合格的工作油液及滤清器,以及其因他不当行为致使车辆出现故障的,由乙方自行承担责任。 </div>
<div>7、乙方所购汽车如在保修期内出现质量问题,甲方(生产厂)应明确承担维修任务的维修站(厂)负责免费维修。</div>
<div>8、以上条款未尽事宜,按照国家有关汽车产品修理、更换、退货的规定、机动车维修管理规定和生产厂的有关汽车产品修理、更换、退货的规定和操作流程执行。</div>
<div>9、乙方所购车辆如属生产厂公布的汽车召回范围,甲方应当召回。</div>
<div>第九条 不可抗力</div>
<div>任何一方因不可抗力的原因,致使车辆不能交接或逾期交接的,可免除违约责任。遇有不可抗力的一方,应负有及时通知并在10日内提供不能履行合同的书面证明。</div>
<div>第十条 违约责任</div>
<div>除本同第七条规定的特殊情况外:</div>
<div>1、若甲方逾期交车,自逾期之日起至实际交付之日,甲方按日向乙方支付车价款万分之伍的违约金,合同继续履行,逾期超过陆拾天,乙方有权解除合同。合同解除后,甲方应当自乙方解除合同之日起陆拾日内退还已付款。</div>
<div>2、若乙方逾期付款,自逾期之日起至实际支付之日,乙方按日向甲方支付车价款万分之伍的违约金,合同继续履行,逾期超过陆拾天,甲方有权解除合同。</div>
<div>3、经甲乙双方约定的或有关行政部门依法认定的汽车检验机构鉴定乙方所购汽车存在设计、制造缺陷,造成的人身、财产损害的,甲方应依法承担责任。</div>
<div>第十一条 争议的解决方式</div>
<div>甲、乙双方在履行本合同过程中发生争议,应协商解决,也可请求消费者协会或其他机构调解。协商不能解决或调解不成的,依法向甲方所在地人民法院起诉。</div>
<div>第十二条 其他</div>
<div>1、双方应保证在合同中填写的姓名、地址、电话等内容真实有效,若有改变,应及时书面通知对方,否则由此造成的损失及相关责任由变更方负责。本合同约定的联系地址和联系方式,亦可作为司法送达的法定地址。</div>
<div>2、本合同的未尽事宜及本合同在履行过程中需变更的事宜,双方可通过订立补充条款或补充协议进行约定。补充条款、补充协议及附件均为不可分割的部分。  </div>
<div>3、本合同及其补充条款、补充协议及附件中的手写文字与打印文字有矛盾时,以手写文字为准。如阿拉伯数字与大写数字有矛盾时,以大写数字为准。  </div>
<div>4、本合同自双方签字或盖章之日起生效,本合同壹式叁份,具有同等效力</div>
<div style="margin-top:50px;">
<table style="width:100%;">
<tr>
<td style="width:60%;">
<div>甲方(盖章)</div>
<div>日期:<?=$day?></div>
</td>
<td style="width:40%;">
<div>乙方(盖章)</div>
<div>日期:<?=$day?></div>
</td>
</tr>
</table>
</div>
</div>
</body>
</html>
@@ -0,0 +1,31 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>车辆信息确认单</title>
</head>
<body>
<div style="font-size:14px;">
<div style="text-align:center;font-weight:bold;font-size:16px;">车辆信息确认单</div>
<div>甲方(出卖人):厦门狸车科技有限公司</div>
<div>乙方(买受人):<?=$name?></div>
<div>乙方于<?=date('Y年m月d日',$c_time)?>在甲方购买 <?=$brand_name?> 车辆 1 台,并确认车架号为:<?=$vin?>。乙方已对上述车辆的厂牌型号、配置等进行认真检查并验收合格无异议。</div>
<div style="margin-top:50px;">
<table style="width:100%;">
<tr>
<td style="width:60%;">
<div>甲方(盖章)</div>
<div>日期:<?=$day?></div>
</td>
<td style="width:40%;">
<div>乙方(盖章)</div>
<div>日期:<?=$day?></div>
</td>
</tr>
</table>
</div>
</div>
</body>
</html>
+133
View File
@@ -0,0 +1,133 @@
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
<title>车辆信息确认单</title>
</head>
<body>
<div style="font-size:14px;">
<div style="text-align:center;font-weight:bold;font-size:16px;">车辆信息确认单</div>
<div style="text-align:right;">合同编号:<?=$cid?></div>
<div>甲方(出卖人):厦门狸车科技有限公司</div>
<div>乙方(买受人):<?=$name?></div>
<div>
<table style="width:100%;">
<tr>
<td style="width:50%;">
身份证:350XXXXXXXXXXXXX
</td>
<td style="width:50%;">
联系电话:<?=$mobile?>
</td>
</tr>
</table>
</div>
<div>一、车辆信息</div>
<div>
<table style="width:100%;">
<tr>
<td style="width:50%;">
车辆品牌:<?=$brand_name?>
</td>
<td style="width:50%;">
颜色:<?=$color?>
</td>
</tr>
<tr>
<td style="width:50%;">
车身号:
</td>
<td style="width:50%;">
车牌号:
</td>
</tr>
</table>
</div>
<div>二、车辆结算信息</div>
<div>
<table style="width:100%;">
<tr>
<td style="width:50%;">
合同售价:<?=number_format($price,2)?> 元
</td>
<td style="width:50%;">
付款方式:<?=$payway?'全款':'分期'?>
</td>
</tr>
<?if(!$payway){?>
<tr>
<td style="width:50%;">
按揭银行:农业银行
</td>
<td style="width:50%;">
贷款期数:36
</td>
</tr>
<?}?>
</table>
</div>
<div>三、代理款信息</div>
<div>
<table style="width:100%;">
<tr>
<td style="width:50%;">
购置税 :
</td>
<td style="width:50%;">
保险:
</td>
</tr>
<tr>
<td style="width:50%;">
保险风险金:
</td>
<td style="width:50%;">
代收利息:
</td>
</tr>
<tr>
<td style="width:50%;">
上牌服务费:
</td>
<td style="width:50%;">
抵押解押服务费:
</td>
</tr>
<tr>
<td style="width:50%;" colspan="2">
新车安全服务包:
</td>
</tr>
</table>
</div>
<div>四、新车交付信息</div>
<div>
<table style="width:100%;">
<tr>
<td style="width:50%;">
整车钥匙两把
</td>
<td style="width:50%;">
车辆登记证
</td>
</tr>
<tr>
<td style="width:50%;">
机动车定期检验合格证
</td>
<td style="width:50%;">
保养协议
</td>
</tr>
</table>
</div>
<div style="margin-top:50px;">
<div>销售顾问:</div>
<div>日期:<?=$day?></div>
</div>
</div>
</body>
</html>
+5
View File
@@ -0,0 +1,5 @@
{
"require": {
"gregwar/image": "^2.1"
}
}
+126
View File
@@ -0,0 +1,126 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "5399d8ff7664d8e39081f1096a99aeef",
"packages": [
{
"name": "gregwar/cache",
"version": "v1.0.13",
"target-dir": "Gregwar/Cache",
"source": {
"type": "git",
"url": "https://github.com/Gregwar/Cache.git",
"reference": "184cc341c25298ff7d584f86b55b6ca26626da4f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Gregwar/Cache/zipball/184cc341c25298ff7d584f86b55b6ca26626da4f",
"reference": "184cc341c25298ff7d584f86b55b6ca26626da4f",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": ">=5.3"
},
"type": "library",
"autoload": {
"psr-0": {
"Gregwar\\Cache": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gregwar",
"email": "g.passault@gmail.com"
}
],
"description": "A lightweight file-system cache system",
"keywords": [
"cache",
"caching",
"file-system",
"system"
],
"time": "2021-04-20T07:23:58+00:00"
},
{
"name": "gregwar/image",
"version": "v2.1.0",
"target-dir": "Gregwar/Image",
"source": {
"type": "git",
"url": "https://github.com/Gregwar/Image.git",
"reference": "1cf64c34cbb22933b36727c16b15ed4d925b6fc6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Gregwar/Image/zipball/1cf64c34cbb22933b36727c16b15ed4d925b6fc6",
"reference": "1cf64c34cbb22933b36727c16b15ed4d925b6fc6",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"ext-gd": "*",
"gregwar/cache": "^1.0.6",
"php": "^5.6 || ^7.0 || ^8.0"
},
"require-dev": {
"sllh/php-cs-fixer-styleci-bridge": "~1.0",
"symfony/phpunit-bridge": "^2.7.4 || ^3.0"
},
"suggest": {
"behat/transliterator": "Transliterator provides ability to set non-latin1 pretty names"
},
"type": "library",
"autoload": {
"psr-0": {
"Gregwar\\Image": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Grégoire Passault",
"email": "g.passault@gmail.com",
"homepage": "http://www.gregwar.com/"
}
],
"description": "Image handling",
"homepage": "https://github.com/Gregwar/Image",
"keywords": [
"gd",
"image"
],
"time": "2021-02-17T16:00:53+00:00"
}
],
"packages-dev": [],
"aliases": [],
"minimum-stability": "stable",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"plugin-api-version": "1.1.0"
}
+3
View File
@@ -25,6 +25,9 @@ if ( ! function_exists('create_order_no'))
case 'liche':
$source_id = sprintf("%02d", 1);
break;
case 'licheb':
$source_id = sprintf("%02d", 2);
break;
default:
$source_id = sprintf("%02d", 0);
}
+6
View File
@@ -64,6 +64,9 @@ class Mycurl
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
//关闭https验证
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
if($this->headers)
{
@@ -109,6 +112,9 @@ class Mycurl
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_ENCODING, ''); // 重要,否则采集数据时会乱码,乱码检测的编码格式为cp936
//关闭https验证
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
if ($file_path && $type=='is_file')
{
+80
View File
@@ -0,0 +1,80 @@
<?php
/**
* Created by Vim
* User: lcc
* Date: 2021/07/12
* Time: 16:49
*/
defined('BASEPATH') OR exit('No direct script access allowed');
require_once COMMPATH.'/third_party/TCPDF/tcpdf.php';
class Pdf {
private $pdf2img_url = 'https://open.xiaoyu.com/jar/pdf2img/index';
public function __construct($isdev=''){
if($isdev){
$this->pdf2img_url = 'https://liche-api-dev.xiaoyu.com/jar/pdf2img';
}
}
/**
* html转pdf
* @param $html_url string 网页地址
* @param $path string 保存文件路径
* @param $filename string 保存文件名
*/
public function html2pdf($html_url,$path,$filename){
if (!file_exists($path)){
$oldumask = umask(0);
mkdir($path, 0777, true);
umask($oldumask);
}
$arrContextOptions=array(
"ssl"=>array(
"verify_peer"=>false,
"verify_peer_name"=>false,
),
);
$html = file_get_contents($html_url,false,stream_context_create($arrContextOptions));
$pdf = new TCPDF(PDF_PAGE_ORIENTATION, PDF_UNIT, PDF_PAGE_FORMAT,true, 'UTF-8', false);
$pdf->SetCreator(PDF_CREATOR);
$pdf->SetAuthor("liche");
$pdf->setPrintHeader(false);
$pdf->setPrintFooter(false);
$pdf->SetDefaultMonospacedFont(PDF_FONT_MONOSPACED);
$pdf->SetMargins(PDF_MARGIN_LEFT, 5,PDF_MARGIN_RIGHT);
$pdf->SetHeaderMargin(PDF_MARGIN_HEADER);
$pdf->SetFooterMargin(PDF_MARGIN_FOOTER);
$pdf->SetAutoPageBreak(TRUE, PDF_MARGIN_BOTTOM);
$pdf->setImageScale(PDF_IMAGE_SCALE_RATIO);
$pdf->SetFont('simsun', '', 10); //设置中文显示
$pdf->AddPage();
$pdf->writeHTML($html, true, false, true, false, '');
$save = $path.'/'.$filename;
$pdf->Output($save,'F');
if(file_exists($save)){
return true;
}else{
return false;
}
}
/*
* 图片转pdf
* @param $pdf_url staring pdf文件url地址
* @return $result array() 返回图片数组 ['','']
*/
public function pdf2img($pdf_url){
$ci = & get_instance();
$ci->load->library('mycurl');
$url = $this->pdf2img_url.'?furl='.$pdf_url;
$result = $ci->mycurl->httpGet($url);
$result = json_decode($result,true);
return $result['data'] ? $result['data'] : false;
}
}
@@ -0,0 +1,63 @@
<?php
/**
* 客户
*/
class Customers_entity{
private $ci;
private $level = ['H','A','B','C','D'];
public function __construct(){
$this->ci = & get_instance();
}
/**
* 添加日志
* @param $customer_id int 客户id
* @param $uid int 操作用户id
* @param $uname int 操作用户名
* @param $content string 日志内容
* @param $type int 操作类型 (0普通日志 1短信 2拨打电话)
*/
public function add_log($customer_id,$uid,$uname,$content,$type=''){
$this->ci->load->model('receiver/receiver_customer_oplogs_model','customer_oplogs_model');
$add_data = [
'customer_id' => $customer_id,
'uid' => $uid,
'log' => $content,
'c_time' => time()
];
$uname && $add_data['uname'] = $uname;
$type && $add_data['type'] = $type;
$result = $this->ci->customer_oplogs_model->add($add_data);
return $result;
}
/**
* 购车时间计算用户等级
* @param $buy_time int 预计购车时间戳
* @param $c_time int 创建时间
*/
public function cal_level($buy_time,$c_time){
$time = $buy_time - $c_time;
if($time<=3*24*60*60){
$level = 'H';
}elseif($time>3*24*60*60 && $time<=7*24*60*60){
$level = 'A';
}elseif($time>7*24*60*60 && $time<=15*24*60*60){
$level = 'B';
}elseif($time>15*24*60*60 && $time<=30*24*60*60){
$level = 'C';
}else{
$level = 'D';
}
return $level;
}
//返回用户等级数组
public function get_level(){
return $this->level;
}
}
?>
@@ -0,0 +1,91 @@
<?php
/**
* 订单
*/
class Orders_entity{
private $ci;
public function __construct(){
$this->ci = & get_instance();
}
/*
* 获取合同h5地址
* @param $id int 订单id
* @param $type int 合同类型(0整车合同 1代理协议 2确定信息 3交接信息)
*/
public function get_contract_h5($id,$type,$wxapp=''){
$url = http_host_com('api');
$res = $path = '';
switch($type){
case 0;
$path = '/wxapp/licheb/protocol/car';
break;
case 1:
$path = '/wxapp/licheb/protocol/agent';
break;
case 2:
$path = '/wxapp/licheb/protocol/car_ck';
break;
case 3:
$path = '/wxapp/licheb/protocol/car_fn';
break;
default:
}
if($path){
$res = $url.$path.'?id='.$id.'&wxapp='.$wxapp;
}
return $res;
}
/**
* 创建定金消费订单
* @param $oid int 订单id
* return boolean
*/
public function c_order($oid,$app_id,$userinfo){
$this->ci->load->model('receiver/order/receiver_orders_model','orders_model');
$this->ci->load->model('apporder/order_purchase_model');
$this->ci->load->model('auto/auto_series_model');
$this->ci->load->model('auto/auto_brand_model');
$row = $this->ci->orders_model->get(['id'=>$oid]);
if(!$row){
return false;
}
$brand = $this->ci->auto_brand_model->get(['id'=>$row['brand_id']],'name');
$series = $this->ci->auto_series_model->get(['id'=>$row['s_id']],'name');
$car_json = json_decode($row['car_json'],true);
$color = isset($car_json['color']) ? $car_json['color'] : '';
$sid = create_order_no(350200,'liche',1,2);
$jsondata['car'] = $car_json;
if($color['jsondata']['img']){
$jsondata['cover'] = $color['jsondata']['img'];
}
$add_data = [
'app_id' => $app_id,
'app_uid' => $userinfo['uid'],
'sid' => $sid,
'item_id' => $row['id'],
'item_title' => $brand['name'].$series['name'],
'item_num' => 1,
'type' => 4,
'item_price' => $row['deposit'],
'total_price' => $row['deposit'],
'uname' => $userinfo['nickname'],
'mobile' => $userinfo['mobile'],
'payway' => 1,
'status' => 1,
'status_detail' => 11,
'jsondata' => json_encode($jsondata,JSON_UNESCAPED_UNICODE),
'c_time' => time(),
'cf_id' => $oid
];
$result = $this->ci->order_purchase_model->add($add_data);
return $result;
}
}
?>
+122
View File
@@ -0,0 +1,122 @@
<?php
/**
* 协议签名
*/
use Gregwar\Image\Image;
class Sign_entity{
private $ci;
private $comp_img = 'https://qimg.haodian.cn/hdi/2021/07/f2308e9066d290eb/79063515aefc302f.png'; //公司印章图片地址
public function __construct(){
$this->ci = & get_instance();
}
/**
* 图片签名
* @param $orgin_url string 签名图片地址
* @param $user_image string 用户签名图片地址
* @param $width int 用户签名x坐标
* @param $height int 用户签名y坐标
* @param $o_width int 公司签名x坐标
* @param $o_height int 公司签名y坐标
* @param $need_c boolean 是否需要公司章
* @param $s_path string 图片保存地址
* return string 返回合成后图片地址
*/
public function merge($origin_url,$user_file,$width,$height,$o_width='',$o_height='',$need_c=true,$s_path='' ){
$arrContextOptions=array(
"ssl"=>array(
"verify_peer"=>false,
"verify_peer_name"=>false,
),
);
//临时保存签名图片
if (!file_exists(FCPATH.'/temp')){
$oldumask = umask(0);
mkdir(FCPATH.'/temp', 0777, true);
umask($oldumask);
}
$file_name = time().rand(1,9999999);
!$s_path && $s_path = FCPATH.'temp/'.md5('sign'.$file_name).'.jpg';
$yhdata = file_get_contents($user_file,false,stream_context_create($arrContextOptions));
$yh_image = Image::fromData($yhdata)->cropResize(150,150);
//原始签名文件
$data = file_get_contents($origin_url,false,stream_context_create($arrContextOptions));
$imgobj = Image::fromData($data);
if($need_c){
!$o_height && $o_height = $height;
//公司
$gs_data = file_get_contents($this->comp_img,false,stream_context_create($arrContextOptions));
$gs_image = Image::fromData($gs_data)->cropResize(200,200);
$imgobj->merge($gs_image,$o_width,$o_height);
}
$imgobj->merge($yh_image,$width,$height)->save($s_path);
if(file_exists($s_path)){
return str_replace(FCPATH,'',$s_path);
}else{
return false;
}
}
/**
* 图片签名
* @param $orgin_url string 签名图片地址
* @param $user_image base64 用户签名文件对象
* @param $width int 用户签名x坐标
* @param $height int 用户签名y坐标
* @param $o_width int 公司签名x坐标
* @param $o_height int 公司签名y坐标
* @param $need_c boolean 是否需要公司章
* @param $s_path string 图片保存地址
* return string 返回合成后图片地址
*/
public function test($origin_url,$user_file,$width,$height,$o_width='',$o_height='',$need_c=true,$s_path='' ){
$user_file = "iVBORw0KGgoAAAANSUhEUgAAAXcAAAKdCAMAAADvKdm1AAAAAXNSR0IB2cksfwAAAFFQTFRFAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAXKkVQgAAABt0Uk5TADCA/99A78/Q8CAQwKBwv+BQkLBgr59/P2+PuKEyZQAAC7pJREFUeJzt3ely6zYMhuHKuy0v8ZJz2t7/hdaCvCTxJskkPvXgff51ppPSGJUEQVD66y8AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA+J8oCvUIQhoMh6OxehABTYbD4VQ9iIBmx7jP1YMIqHreB+pBxLM4hn1YqkcRz/gY9qV6EAEd05nhSj2IgFZM7xLLY9xJ392V1bK6UI8inhXZu0JRPe5r9Sji2RzD/qEeRDzbIauqwohNk8KAZEahrEpiO/Uo4qke9zklMW8lFWAJHncJHncNHncJHncNHncJHncNHncJHncNHncNHneJMY+7xI6mGYnqvGOrHkQ8BT2REutj2PfqQQQ0Pcb9oB5EPAuOVSUOx7DP1IMIaE+PmIK1onJ30t2W3jyJFV0zClYCpifSHR3vEnS8a9DxLnGg412hHFESU6DjXcIqYpyruvusFlUOPLxVx9kU3v1xjUxiTSFSwQozdG+0keRVgwealVqyrLtXRiG6bybqMN+aRAj8TB3lOyK8crJczdVhvkFDQjPVcUeq3H07G35EmGcSsMoMsXJXpUQcd7izPROVGXfsmTSqihh1d3f2HjGOmdxVTQRUxNxZzwwFYHcp90xobHHa2scoIvbHpYw8Ya5xtLiWkUek8H4+v1QRN+rBxGG5e9UAXF2O58KBl/LavFF92oAijZPdNXcvP1hbvViL2LkyU1THVhEO6PSm3+ruB6Z4H5a6f7lmsOfYycPiZ4tYPcWTxWe2uTnuKMji8zvcmVUGXxda5GCHqjd1yCVF4czshvDNKVM5p1CT1fjBjGKFg0//8QRhBYK73XQ76gUZDR7P41Wf64Rj7iyKJ1tTqxeQTGZh7yF4tHquz7VhJLZ+XhBYMtNkYan7k/cQLJhpsvh81Q/JTJPD+HVUmWkyeJi6XzHTpPckdb9ipklt0exUiZkmsduq+13MNGltm57lMdOkdL/qfhczTUK75nc7FvR1JFO0Ocdbc+iXyveGmVf2HPqlsf7RMPMCh35p2CzT5r2cVlH4lW08QVifUrv7wTs6yN5WTtufnJYzOsje9dklPaGD7F02ZbS/Hsy29T3WlTfrMGPQQfYOmy86vXODbesb6lSm21O75TpCV11SmatVu90WLjqlMhdcR+ioYypzMaZXtYvOqczFgF7V9or25YEbM5LJtqzjumMqc2HJJJeK29gkmSNsrpqytjaW6n0PNsWzfWrKntMkb7FaUYtvztbURN8GmnHc2lSSNfXyx2Zkkw2lWVPP7AIOHTWvpX6HUsHa2kS6NfXbX2SKfy7lmnq2pzT5StI19fJHP+ioeSHtmnpGafKFXO8lpDT5VPo19Yxr9E/kWFNPOOd+LMuaekYy+VCeNfWMZPKBzO/6JZm8L9+aekIyeY9FJe934UkmbxVvtIY1xjn3T/X3C3I/i5xz//BeR15ztoawtp7VYff4CNaaBoMvfnmF/XTOTVJjLOxe31je02Bwsn67EbKN+pybKzj1Wuf4HVXbt5LG12H3zO2swSB6Gm9hdw6CNRjETuPrsHv/Tx8+jdeEPXwarwp78DReF/bQabwy7IHT+MKlBPlQ1DTeDrGVvztoGp/3ELuJkGl8Hz5YG/DWWfZD7EbC3To75D/EbiTYrTP/WtgjoW6dSRP37yLdOutR2CPdOutV2MO8em877VfYT7XJ3+pR5DbqW9hPr96b/uGdwj2silgX2TGd1Ke1GW1nw3nf3tx7qAM/+f1HR76HSts/HSP/h082/TO2PH44Uo8jnvW8fytPCCWB19j2L8WNwXbSvGHVH3dcRQZRimQ9U/JZRQ2+TyGyDHbi2hdVkWyuHkREh+GcKg0AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBmfxfqEYS04+t6CvZlePUgAqq+VL9UDyIe+9QYnwByNzmGfa8eRDzjY9jnfDvV3TGZGa7UgwhodIz7Vj2IeBbVqso0427Nqiqx5Hu1CmU1zfBhbHfVl+Bn6kEEtDrGfaceRDxltVmlCOyummb4Kra/atM0UA8ingObJokNtRmFMcm7xJ4agcKCgyaJFeeqClaaoX/D3eAY9g/1IOKxEgGPu7sD59kSlAgk2DNpUCKQYM+kwZ5JgiRSgz2TBkmkBHsmDZJICfZMGiSREuyZNEgiNdgzSZBEakxpAVYoSCIlVjQrKVglknuT7tYkkRJUIiXGdLxLrKhEKlCa0aA0ozGiNKOwpTQjwfmehK2q3M52t+N8T4EmMY0VLyNQsMI7r1Zyt2HPpHCgRKBQjkhmFAYcqyosJpx3KHxSmVEY8y4CiSmviVQgh5Swwgz1X3dVHXJODunNyu7kkO6sMEMO6c1ySDoi3VGYkRhwqKqwIIeUoDAjseVwT4HTDo0di6rCmJ2qxJQWAoUB5V8FUneNDam7woF6mIIdMpG6u1txyKRA6i5hBQI6N9xRdZewOwa8VMkdR9kSa1J3BSsQTP/meXdWlSErIx55T4Ph2YRH3o/tmPbLIRsnV7ZjmpeL1YwH3tOv82FHOeeB97O97piqeX5CZcyFpZCnuow98J/a8USx+VqXYfvkZf29PaxaWkcsrdlZOWz5458pj+VWTn+eZNMv5mF3M5+XH1WlRjWeIGyj+qNfhn7g7KyB4KbovqdnLLPPu3P5okriJ0zx2awf1MGsfYnA52Ip490GAgv8lCw+C6sPPGhTWhH4XCxzf/iCGQv8xnVAQXw+P+SwQ5BfjuMJYncnc/+qnBH4DGzlnD2bwOvA86KrpCyVeXHBoJgT+MTqVOZVgl6wf0rreSpzZdUbivHJvEhlrg5kkwm9SmV+/qucgiTxOpX5Ysnamki9pjadtO0UhLU1gU2TVObKkhrW1rcN2p4msbamYBumdt9sZm1N4KZ9oAHW1rfdtg80YGsrgX/DvfaBBqjUvMf63Lvc2bO1lcB3delzb43Av2H7RmJC4Dsrv/S5t0fgu7rfpNQYge/mUZNSYwS+i+L9dykR+Pbqq5Jv3hgj8K1tkkSMwLeUqrZF4FuxcCV5UV4deC78NVLcvV7QDT3ajdVraqpQEfim0qypFwS+meTnRXXgOXJ9Lt2aesGthNfsqCP1e/II/CtFow7U1gj8c9aklGOfY3dceWHKA00bfzv8Za6DPFaHPc9nIwj8Y7/yhZ3AP2Zhz/di8ZLujrvWbfqtu6Ct5h7bL+X9Ng2Bv9Xs6tibCPyNb2/Jy2bLOch3P96Slw0HUN8s3L7EROC/2iToHmiIwF95zTKGwJ9lKLm//M8R+FPm7vhWawJfEUSBwItiQOBFEYgeeNnvjx144a+PHHjpb48bePEvjxr4f9S/O2TgFxv9rw4X+O35u4bi3xwt8KM66nP5L64D/696GF7sjRnDZQ++NFYH/jNIC992dnzY+/FNjoOduU578AgEUx92T/hAiLe6kyzQ6toXpbVp08Pnzw4ah5sgq2uPbG2SH3H7zFthqe2EG8beyvoz6f+oxxHPaXVlkvdW7125fuZuXG+hWF29LWwLNWEL5a3cxypQ9seOSV7jwCSvUW+hyOTdnbZQZPLuBkMOQyTqOhnlGndFfRjyWz2OcE6HIVFOvHukPgyhJu/uVK6hauCtZJIXoSYvQk1epODEW+NUk2cL5e1UriGtcUc/mciBfjKNLd3aGqd+MtIab3Rri5wKlATe3YC0RuNA4DXqyjD5pLu6WkOZzF197joln/RW55Mk8u7qMhn3Xf2RyIusmGo0DmQ1Ggc2UBorpngJSyeZ4v3ZzpUp3h9TvAhTvAZTvIhN8SOmeHc2xW/Uowgo+TfY0cyStVWi/GBtlWD7JML2SYTtk0a9fVKPIiCb4lla/VXvaOrHy71jqS5279WDCKhggteoMhr1GCIi7hrEXYO4axB3DeKu8TEcztRjiGg7++C1EQAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAoLf+A6jRZVspl5i5AAAAAElFTkSuQmCC";
$arrContextOptions=array(
"ssl"=>array(
"verify_peer"=>false,
"verify_peer_name"=>false,
),
);
//临时保存用户签名图片
if (!file_exists(FCPATH.'/temp')){
$oldumask = umask(0);
mkdir(FCPATH.'/temp', 0777, true);
umask($oldumask);
}
$file_name = time().rand(1,9999999);
!$s_path && $s_path = FCPATH.'temp/'.md5('sign'.$file_name).'.jpg';
$imgPath = FCPATH.'temp/'.md5($file_name).'.png';
$res = file_put_contents($imgPath,base64_decode($user_file));
if(!$res){
return false;
}
$yh_image = Image::open($imgPath)->cropResize(150,150);
//原始签名文件
$data = file_get_contents($origin_url,false,stream_context_create($arrContextOptions));
$imgobj = Image::fromData($data);
if($need_c){
!$o_height && $o_height = $height;
//公司
$gs_data = file_get_contents($this->comp_img,false,stream_context_create($arrContextOptions));
$gs_image = Image::fromData($gs_data)->cropResize(200,200);
$imgobj->merge($gs_image,$o_width,$o_height);
}
$imgobj->merge($yh_image,$width,$height)->save($s_path);
@unlink($imgPath);
if(file_exists($s_path)){
return str_replace(FCPATH,'',$s_path);
}else{
return false;
}
}
}
@@ -0,0 +1,20 @@
<?php
/**
* Created by Vim
* User: lcc
* Date: 2021/06/29
* Time: 13:47
*/
defined('BASEPATH') OR exit('No direct script access allowed');
class Receiver_customer_oplogs_model extends HD_Model
{
private $table_name = 'lc_receiver_customer_oplogs';
public function __construct()
{
parent::__construct($this->table_name, 'default');
}
}
@@ -12,9 +12,13 @@ class Receiver_customers_model extends HD_Model
{
private $table_name = 'lc_receiver_customers';
private $status_arr = [-1 => '删除',0 => '未见客户',1 => '到店客户',2 => '订单客户',3 => '战败客户'];
public function __construct()
{
parent::__construct($this->table_name, 'default');
}
public function get_status(){
return $this->status_arr;
}
}
@@ -0,0 +1,20 @@
<?php
/**
* Created by Vim
* User: lcc
* Date: 2021/07/13
* Time: 13:47
*/
defined('BASEPATH') OR exit('No direct script access allowed');
class Receiver_order_ckcars_model extends HD_Model
{
private $table_name = 'lc_receiver_order_ckcars';
public function __construct()
{
parent::__construct($this->table_name, 'default');
}
}
@@ -0,0 +1,25 @@
<?php
/**
* Created by Vim
* User: lcc
* Date: 2021/07/12
* Time: 13:47
*/
defined('BASEPATH') OR exit('No direct script access allowed');
class Receiver_order_contracts_model extends HD_Model
{
private $table_name = 'lc_receiver_order_contracts';
private $type_arr = [ 0 => '整车合同',1 => '代理协议',2 => '车辆信息确定',3 => '交接信息'];
public function __construct()
{
parent::__construct($this->table_name, 'default');
}
public function get_types(){
return $this->type_arr;
}
}
@@ -0,0 +1,20 @@
<?php
/**
* Created by Vim
* User: lcc
* Date: 2021/07/13
* Time: 13:47
*/
defined('BASEPATH') OR exit('No direct script access allowed');
class Receiver_order_loans_model extends HD_Model
{
private $table_name = 'lc_receiver_order_loans';
public function __construct()
{
parent::__construct($this->table_name, 'default');
}
}
@@ -0,0 +1,20 @@
<?php
/**
* Created by Vim
* User: lcc
* Date: 2021/07/09
* Time: 13:47
*/
defined('BASEPATH') OR exit('No direct script access allowed');
class Receiver_order_signs_model extends HD_Model
{
private $table_name = 'lc_receiver_order_signs';
public function __construct()
{
parent::__construct($this->table_name, 'default');
}
}
@@ -0,0 +1,26 @@
<?php
/**
* Created by Vim
* User: lcc
* Date: 2021/07/09
* Time: 13:47
*/
defined('BASEPATH') OR exit('No direct script access allowed');
class Receiver_orders_model extends HD_Model
{
private $table_name = 'lc_receiver_orders';
private $status_arr = [ 0 => '合同签订',1 => '办理分期',2 => '申请开票',3 => '交付确认', 4 => '申请退款'];
public function __construct()
{
parent::__construct($this->table_name, 'default');
}
public function get_status(){
return $this->status_arr;
}
}
+31 -1
View File
@@ -39,7 +39,7 @@ class Payment_service extends HD_Service{
break;
case 2: //虚拟物品
break;
case 3:
case 3: //活动订单
$upd = array('status'=>2,'status_detail'=>21,'pay_time'=>date('Y-m-d H:i:s'));
$pay_price && $upd['pay_price'] = $pay_price;
$res = $this->purchase_model->update($upd,array('id'=>$order['id']));
@@ -49,6 +49,36 @@ class Payment_service extends HD_Service{
return array('code'=>0,'msg'=>'更新失败');
}
break;
case 4: //定金
$upd = array('status'=>2,'status_detail'=>21,'pay_time'=>date('Y-m-d H:i:s'));
$pay_price && $upd['pay_price'] = $pay_price;
$res = $this->purchase_model->update($upd,array('id'=>$order['id']));
if($res){
//更新订单状态
$this->load->model('receiver/order/receiver_orders_model','orders_model');
$row = $this->orders_model->get(['id'=>$order['item_id']]);
if($row){
if($row['payway']){//全款
$status = 2;
$this->load->model('receiver/order/receiver_order_ckcars_model','next_model');
}else{
$status = 1;
$this->load->model('receiver/order/receiver_order_loans_model','next_model');
}
$res = $this->orders_model->update(['status'=>$status],['id'=>$row['id']]);
if($res){
$add_data = [
'o_id' => $row['id'],
'c_time' => time()
];
$this->next_model->add($add_data);
}
}
return array('code'=>1,'msg'=>'操作成功');
}else{
return array('code'=>0,'msg'=>'更新失败');
}
break;
default:
debug_log("[error] ". __FUNCTION__ . ":{$item['type']}_未知商品类型", $this->log_file);
return array('code'=>0,'msg'=>'未知商品类型');
Binary file not shown.
File diff suppressed because one or more lines are too long
Binary file not shown.
BIN
View File
Binary file not shown.
+167
View File
@@ -0,0 +1,167 @@
<?php
date_default_timezone_set('PRC');
/* 非加密接口demo */
define("YM_SMS_ADDR", "bjksmtn.b2m.cn:80");/*接口地址,请联系销售获取*/
define("YM_SMS_SEND_URI", "/simpleinter/sendSMS");/*发送短信接口*/
define("YM_SMS_SEND_PER_URI", "/simpleinter/sendPersonalitySMS");/*发送个性短信接口*/
define("YM_SMS_GETREPORT_URI", "/simpleinter/getReport");/*获取状态报告接口*/
define("YM_SMS_GETMO_URI", "/simpleinter/getMo");/*获取上行接口*/
define("YM_SMS_GETBALANCE_URI", "/simpleinter/getBalance"); /*获取余额接口*/
define("YM_SMS_APPID", "EUCP-EMY-SMS1-1XCTS");/*APPID,请联系销售或者在页面获取*/
define("YM_SMS_AESPWD", "8B10E95061795393");/*密钥,请联系销售或者在页面获取*/
define("END", "\n");
function http_request($url, $data)
{
print_r($url);
print_r(END);
print_r($data);
print_r(END);
$data = http_build_query($data);
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_POST, TRUE);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
$output = curl_exec($curl);
curl_close($curl);
print_r($output);
return $output;
}
function signmd5($appId,$secretKey,$timestamp){
return md5($appId.$secretKey.$timestamp);
}
//6a81c1e91a7a0c3ea99849bcff98d0a1
// echo signmd5("1673CC0DA7837980","1673CC0DA7837980","15612333333");
//echo phpinfo();
//exit;
function sendSMS()
{
$content = "【某某公司】您的验证码是123&st=xxx";/* 短信内容请以商务约定的为准,如果已经在通道端绑定了签名,则无需在这里添加签名 */
$timestamp = date("YmdHis");
$sign = signmd5(YM_SMS_APPID,YM_SMS_AESPWD,$timestamp);
// 如果您的系统环境不是UTF-8,需要转码到UTF-8。如下:从gb2312转到了UTF-8
// $content = mb_convert_encoding( $content,"UTF-8","gb2312");
// 另外,如果包含特殊字符,需要对内容进行urlencode
$data = array(
"appId" => YM_SMS_APPID,
"timestamp" => $timestamp,
"sign" => $sign,
"mobiles" => "18001000000,18001000001",
"content" => $content,
"customSmsId" => "10001",
// "timerTime" => "20170910110200",
"extendedCode" => "1234"
);
$url = YM_SMS_ADDR.YM_SMS_SEND_URI;
$resobj = http_request($url, $data);
// var_dump($resobj);
}
function setPersonalitySms()
{
$mobile1 = "18001000000";
$content1 = "今天天气不错啊&st=xxx";
$mobile2 = "18001000001";
$content2 = "今天天气不错";
$timestamp = date("YmdHis");
$sign = signmd5(YM_SMS_APPID,YM_SMS_AESPWD,$timestamp);
// 如果您的系统环境不是UTF-8,需要转码到UTF-8。如下:从gb2312转到了UTF-8
// $content = mb_convert_encoding( $content,"UTF-8","gb2312");
// 另外,如果包含特殊字符,需要对内容进行urlencode
$data = array(
"appId" => YM_SMS_APPID,
"timestamp" => $timestamp,
"sign" => $sign,
$mobile1 => $content1,
$mobile2 => $content2,
"customSmsId" => "10001",
// "timerTime" => "20170910110200",
"extendedCode" => "1234"
);
$url = YM_SMS_ADDR.YM_SMS_SEND_PER_URI;
$resobj = http_request($url, $data);
}
function getReport()
{
$timestamp = date("YmdHis");
$sign = signmd5(YM_SMS_APPID,YM_SMS_AESPWD,$timestamp);
$data = array(
"appId" => YM_SMS_APPID,
"timestamp" => $timestamp,
"sign" => $sign,
"number" => "300"
);
$url = YM_SMS_ADDR.YM_SMS_GETREPORT_URI;
$resobj = http_request($url, $data);
}
function getMo()
{
$timestamp = date("YmdHis");
$sign = signmd5(YM_SMS_APPID,YM_SMS_AESPWD,$timestamp);
$data = array(
"appId" => YM_SMS_APPID,
"timestamp" => $timestamp,
"sign" => $sign,
"number" => "300"
);
$url = YM_SMS_ADDR.YM_SMS_GETMO_URI;
$resobj = http_request($url, $data);
}
function getBalance()
{
$timestamp = date("YmdHis");
$sign = signmd5(YM_SMS_APPID,YM_SMS_AESPWD,$timestamp);
$data = array(
"appId" => YM_SMS_APPID,
"timestamp" => $timestamp,
"sign" => $sign
);
$url = YM_SMS_ADDR.YM_SMS_GETBALANCE_URI;
$resobj = http_request($url,$data);
return $resobj;
}
function run(){
echo "***************测试短信发送START***************\n".END;
SendSMS();
echo END;
echo "***************测试短信发送END***************".END;
echo "***************测试个性短信发送START***************".END;
setPersonalitySms();
echo END;
echo "***************测试个性短信发送END***************".END;
echo "***************测试获取余额START***************".END;
getBalance();
echo END;
echo "***************测试获取余额END***************".END;
echo "***************测试获取状态报告START***************".END;
getReport();
echo END;
echo "***************测试获取状态报告END***************".END;
echo "***************测试获取上行START***************".END;
getMo();
echo END;
echo "***************测试获取上行END***************".END;
}
//run();
?>
+470
View File
@@ -0,0 +1,470 @@
<?php
date_default_timezone_set('PRC');
define("YM_SMS_ADDR", "bjksmtn.b2m.cn:80");/*接口地址,请联系销售获取*/
define("YM_SMS_SEND_URI", "/inter/sendSingleSMS");/*发送单条短信接口*/
define("YM_SMS_SEND_BATCH_URI", "/inter/sendBatchSMS");/*发送批次短信接口*/
define("YM_SMS_SEND_BATCHONLY_SMS_URI", "/inter/sendBatchOnlySMS");/*发送批次[不支持自定义smsid]短信接口*/
define("YM_SMS_SEND_PERSONALITY_SMS_URI", "/inter/sendPersonalitySMS");/*发送个性短信接口*/
define("YM_SMS_GETREPORT_URI", "/inter/getReport");/*获取状态报告接口*/
define("YM_SMS_GETMO_URI", "/inter/getMo");/*获取上行接口*/
define("YM_SMS_GETBALANCE_URI", "/inter/getBalance"); /*获取余额接口*/
define("YM_SMS_APPID", "EUCP-EMY-SMS1-1XCTS");/*APPID,请联系销售或者在页面获取*/
define("YM_SMS_AESPWD", "8B10E95061795393");/*密钥,请联系销售或者在页面获取*/
define("EN_GZIP", true);/* 是否开启GZIP */
define("END", "\n");
class MagicCrypt
{
private $iv = "0102030405060708";//密钥偏移量IV,可自定义
private $encryptKey = YM_SMS_AESPWD;
//加密
public function encrypt($encryptStr)
{
if (version_compare(PHP_VERSION, '7.0.0', 'ge')) {
$encryptObj = new MagicCrypt();
return $encryptObj->encryptPhp7($encryptStr);//加密结果
}
$localIV = $this->iv;
$encryptKey = $this->encryptKey;
if (true == EN_GZIP) $encryptStr = gzencode($encryptStr);
//Open module
$module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, $localIV);
mcrypt_generic_init($module, $encryptKey, $localIV);
//Padding
$block = mcrypt_get_block_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_ECB);
$pad = $block - (strlen($encryptStr) % $block); //Compute how many characters need to pad
$encryptStr .= str_repeat(chr($pad), $pad); // After pad, the str length must be equal to block or its integer multiples
//encrypt
$encrypted = mcrypt_generic($module, $encryptStr);
//Close
mcrypt_generic_deinit($module);
mcrypt_module_close($module);
return $encrypted;
}
//PHP7使用这个加密
public function encryptPhp7($encryptStr)
{
$localIV = $this->iv;
$encryptKey = $this->encryptKey;
if (true == EN_GZIP) $encryptStr = gzencode($encryptStr);
return openssl_encrypt($encryptStr, 'AES-128-ECB', $encryptKey, OPENSSL_RAW_DATA, $localIV);
}
//解密
public function decrypt($encryptStr)
{
if (version_compare(PHP_VERSION, '7.0.0', 'ge')) {
$encryptObj = new MagicCrypt();
return $encryptObj->decryptPhp7($encryptStr);//加密结果
}
$localIV = $this->iv;
$encryptKey = $this->encryptKey;
//Open module
$module = mcrypt_module_open(MCRYPT_RIJNDAEL_128, '', MCRYPT_MODE_ECB, $localIV);
mcrypt_generic_init($module, $encryptKey, $localIV);
$encryptedData = mdecrypt_generic($module, $encryptStr);
if (true == EN_GZIP) $encryptedData = gzdecode($encryptedData);
return $encryptedData;
}
//PHP7使用这个解密
public function decryptPhp7($encryptStr)
{
$localIV = $this->iv;
$encryptKey = $this->encryptKey;
$encryptedData = openssl_decrypt($encryptStr, 'AES-128-ECB', $encryptKey, OPENSSL_RAW_DATA, $localIV);
if (true == EN_GZIP) $encryptedData = gzdecode($encryptedData);
return $encryptedData;
}
}
error_reporting(0);
function http_request($url, $data = null)
{
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_HEADER, true);
$header[] = "appId: " . YM_SMS_APPID;
if (true == EN_GZIP) $header[] = "gzip: on";
// echo END;
// echo "[send head is] :" . END;
// //print_r($header);
// echo $header;
// echo END;
// echo END;
curl_setopt($curl, CURLOPT_HTTPHEADER, $header);
curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
curl_setopt($curl, CURLOPT_HEADER, true);
if (!empty($data)) {
curl_setopt($curl, CURLOPT_POST, 1);
curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, TRUE);
$res = curl_exec($curl);
//var_dump($res);
$headerSize = curl_getinfo($curl, CURLINFO_HEADER_SIZE);
curl_close($curl);
$header = substr($res, 0, $headerSize);
// echo "[result head is] : " . END;
// echo $header;
// echo "URL=" . $url . END;
$outobj = new stdClass();
$lines = explode("\r\n", $header);
foreach ($lines as $line) {
$items = explode(": ", $line);
if (isset($items[0]) and !empty($items[0]) and
isset($items[1]) and !empty($items[1]))
$outobj->$items[0] = $items[1];
}
$outobj->ciphertext = substr($res, $headerSize);
//var_dump($outobj);
return $outobj;
}
function getMillisecond()
{
list($t1, $t2) = explode(' ', microtime());
return (float)sprintf('%.0f', (floatval($t1) + floatval($t2)) * 1000);
}
function SendSMS($mobile, $content,
$timerTime = "", $customSmsId = "",
$extendedCode = "",
$validPeriodtime = 120)
{
// 如果您的系统环境不是UTF-8,内容需要转码到UTF-8。如下:从gb2312转到了UTF-8
// $content = mb_convert_encoding( $content,"UTF-8","gb2312");
$item = new stdClass();
$item->mobile = $mobile;
$item->content = $content;
/* 选填内容 */
if ("" != $timerTime) $item->timerTime = $timerTime;
if ("" != $customSmsId) $item->customSmsId = $customSmsId;
if ("" != $extendedCode) $item->extendedCode = $extendedCode;
$item->requestTime = getMillisecond();
$item->requestValidPeriod = $validPeriodtime;
$json_data = json_encode($item, JSON_UNESCAPED_UNICODE);
// echo "[send json is] :" . END;
// echo "" . $json_data . END;
$encryptObj = new MagicCrypt();
$senddata = $encryptObj->encrypt($json_data);//加密结果
$url = YM_SMS_ADDR . YM_SMS_SEND_URI;
$resobj = http_request($url, $senddata);
$resobj->plaintext = $encryptObj->decrypt($resobj->ciphertext);
return $resobj;
}
function SendBatchSMS($mobiles, $content,
$timerTime = "", $customSmsId = "",
$extendedCode = "",
$validPeriodtime = 120)
{
$item = new stdClass();
$smses = array();
foreach ($mobiles as $mobile) $smses[] = $mobile;
$item->smses = $smses;
// 如果您的系统环境不是UTF-8,内容需要转码到UTF-8。如下:从gb2312转到了UTF-8
// $content = mb_convert_encoding( $content,"UTF-8","gb2312");
$item->content = $content;
/* 选填内容 */
if ("" != $timerTime) $item->timerTime = $timerTime;
if ("" != $customSmsId) $item->customSmsId = $customSmsId;
if ("" != $extendedCode) $item->extendedCode = $extendedCode;
$item->requestTime = getMillisecond();
$item->requestValidPeriod = $validPeriodtime;
$json_data = json_encode($item, JSON_UNESCAPED_UNICODE);
echo "[send json is] :" . END;
echo "" . $json_data . END;
$encryptObj = new MagicCrypt();
$senddata = $encryptObj->encrypt($json_data);//加密结果
$url = YM_SMS_ADDR . YM_SMS_SEND_BATCH_URI;
$resobj = http_request($url, $senddata);
$resobj->plaintext = $encryptObj->decrypt($resobj->ciphertext);
return $resobj;
}
function sendBatchOnlySMS($mobiles, $content,
$timerTime = "", $customSmsId = "",
$extendedCode = "",
$validPeriodtime = 120)
{
// 如果您的系统环境不是UTF-8,内容需要转码到UTF-8。如下:从gb2312转到了UTF-8
// $content = mb_convert_encoding( $content,"UTF-8","gb2312");
$item = new stdClass();
$item->mobiles = $mobiles;
$item->content = $content;
/* 选填内容 */
if ("" != $timerTime) $item->timerTime = $timerTime;
if ("" != $extendedCode) $item->extendedCode = $extendedCode;
$item->requestTime = getMillisecond();
$item->requestValidPeriod = $validPeriodtime;
$json_data = json_encode($item, JSON_UNESCAPED_UNICODE);
echo "[send json is] :" . END;
echo "" . $json_data . END;
$encryptObj = new MagicCrypt();
$senddata = $encryptObj->encrypt($json_data);//加密结果
$url = YM_SMS_ADDR . YM_SMS_SEND_BATCHONLY_SMS_URI;
$resobj = http_request($url, $senddata);
$resobj->plaintext = $encryptObj->decrypt($resobj->ciphertext);
return $resobj;
}
function sendPersonalitySMS($mobiles,
$timerTime = "", $customSmsId = "",
$extendedCode = "",
$validPeriodtime = 120)
{
// 如果您的系统环境不是UTF-8,内容需要转码到UTF-8。如下:从gb2312转到了UTF-8
// $content = mb_convert_encoding( $content,"UTF-8","gb2312");
$item = new stdClass();
$smses = array();
foreach ($mobiles as $mobile) $smses[] = $mobile;
$item->smses = $smses;
/* 选填内容 */
if ("" != $timerTime) $item->timerTime = $timerTime;
if ("" != $customSmsId) $item->customSmsId = $customSmsId;
if ("" != $extendedCode) $item->extendedCode = $extendedCode;
$item->requestTime = getMillisecond();
$item->requestValidPeriod = $validPeriodtime;
$json_data = json_encode($item, JSON_UNESCAPED_UNICODE);
echo "[send json is] :" . END;
echo "" . $json_data . END;
$encryptObj = new MagicCrypt();
$senddata = $encryptObj->encrypt($json_data);//加密结果
$url = YM_SMS_ADDR . YM_SMS_SEND_PERSONALITY_SMS_URI;
$resobj = http_request($url, $senddata);
$resobj->plaintext = $encryptObj->decrypt($resobj->ciphertext);
return $resobj;
}
function getReport($number = 0, $validPeriodtime = 120)
{
$item = new stdClass();
/* 选填内容 */
if (0 != $number) $item->number = $number;
$item->requestTime = getMillisecond();
$item->requestValidPeriod = $validPeriodtime;
$json_data = json_encode($item, JSON_UNESCAPED_UNICODE);
echo "[send json is] :" . END;
echo "" . $json_data . END;
$encryptObj = new MagicCrypt();
$senddata = $encryptObj->encrypt($json_data);//加密结果
$url = YM_SMS_ADDR . YM_SMS_GETREPORT_URI;
$resobj = http_request($url, $senddata);
$resobj->plaintext = $encryptObj->decrypt($resobj->ciphertext);
return $resobj;
}
function getMo($number = 0, $validPeriodtime = 120)
{
$item = new stdClass();
/* 选填内容 */
if (0 != $number) $item->number = $number;
$item->requestTime = getMillisecond();
$item->requestValidPeriod = $validPeriodtime;
$json_data = json_encode($item, JSON_UNESCAPED_UNICODE);
echo "[send json is] :" . END;
echo "" . $json_data . END;
$encryptObj = new MagicCrypt();
$senddata = $encryptObj->encrypt($json_data);//加密结果
$url = YM_SMS_ADDR . YM_SMS_GETMO_URI;
$resobj = http_request($url, $senddata);
$resobj->plaintext = $encryptObj->decrypt($resobj->ciphertext);
return $resobj;
}
function getBalance($validPeriodtime = 120)
{
$item = new stdClass();
$item->requestTime = getMillisecond();
$item->requestValidPeriod = $validPeriodtime;
$json_data = json_encode($item, JSON_UNESCAPED_UNICODE);
echo "[send json is] :" . END;
echo "" . $json_data . END;
$encryptObj = new MagicCrypt();
$senddata = $encryptObj->encrypt($json_data);//加密结果
$url = YM_SMS_ADDR . YM_SMS_GETBALANCE_URI;
$resobj = http_request($url, $senddata);
$resobj->plaintext = $encryptObj->decrypt($resobj->ciphertext);
return $resobj;
}
function run_dev()
{
echo "***************测试单条短信发送***************" . END;
$resobj = SendSMS("18001000000", "【某某公司】您的验证码是123");/* 短信内容请以商务约定的为准,如果已经在通道端绑定了签名,则无需在这里添加签名 */
$resobj->ciphertext = "";
echo "[result json is] :" . END;
echo "" . $resobj->plaintext . END;
echo "***************测试单条短信发送完成***************" . END;
//==========================================================================================
echo "***************测试多条短信发送(支持SMSID)***************" . END;
$mobiles = array();
$mobiles[] = new stdClass();
$mobiles[0]->mobile = "18001000000";
$mobiles[0]->customSmsId = "123";
$mobiles[] = new stdClass();
$mobiles[1]->mobile = "18001000001";
$mobiles[1]->customSmsId = "321";
$resobj = SendBatchSMS($mobiles, "【某某公司】您的验证码是123");/* 短信内容请以商务约定的为准,如果已经在通道端绑定了签名,则无需在这里添加签名 */
$resobj->ciphertext = "";
echo "[result json is] :" . END;
echo "" . $resobj->plaintext . END;
echo "***************测试多条短信发送(支持SMSID)完成***************" . END;
//==========================================================================================
echo "***************测试多条短信发送(不支持SMSID)***************" . END;
$mobiles = array();
$mobiles[] = "18001000000";
$mobiles[] = "18001000001";
$resobj = sendBatchOnlySMS($mobiles, "【某某公司】您的验证码是123");
$resobj->ciphertext = "";
echo "[result json is] :" . END;
echo "" . $resobj->plaintext . END;
echo "***************测试多条短信发送(不支持SMSID)完成***************" . END;
//==========================================================================================
echo "***************测试个性短信接口***************" . END;
$mobiles = array();
$mobiles[] = new stdClass();
$mobiles[0]->mobile = "18001000000";
$mobiles[0]->customSmsId = "1111111";
$mobiles[0]->content = "我是个性1号";
$mobiles[] = new stdClass();
$mobiles[1]->mobile = "18001000001";
$mobiles[1]->customSmsId = "2222222";
$mobiles[1]->content = "我是个性2号";
$mobiles[] = new stdClass();
$mobiles[2]->mobile = "18001000002";
$mobiles[2]->customSmsId = "3333333";
$mobiles[2]->content = "我是个性3号";
$resobj = sendPersonalitySMS($mobiles);
$resobj->ciphertext = "";
echo "[result json is] :" . END;
echo "" . $resobj->plaintext . END;
echo "***************测试个性短信接口完成***************" . END;
//==========================================================================================
echo "***************测试状态报告接口***************" . END;
$resobj = getReport();
$resobj->ciphertext = "";
echo "[result json is] :" . END;
echo "" . $resobj->plaintext . END;
echo "***************测试状态报告接口完成***************" . END;
//==========================================================================================
echo "***************测试上行接口***************" . END;
$resobj = getMo();
$resobj->ciphertext = "";
echo "[result json is] :" . END;
echo "" . $resobj->plaintext . END;
echo "***************测试上行接口完成***************" . END;
//==========================================================================================
echo "***************测试余额接口***************" . END;
$resobj = getBalance();
$resobj->ciphertext = "";
echo "[result json is] :" . END;
echo "" . $resobj->plaintext . END;
echo "***************测试余额接口完成***************" . END;
}
//run_dev();
?>
+7
View File
@@ -0,0 +1,7 @@
<?php
// autoload.php @generated by Composer
require_once __DIR__ . '/composer/autoload_real.php';
return ComposerAutoloaderInitd0872984a1db7aa104ae1184a3170d3e::getLoader();
+445
View File
@@ -0,0 +1,445 @@
<?php
/*
* This file is part of Composer.
*
* (c) Nils Adermann <naderman@naderman.de>
* Jordi Boggiano <j.boggiano@seld.be>
*
* For the full copyright and license information, please view the LICENSE
* file that was distributed with this source code.
*/
namespace Composer\Autoload;
/**
* ClassLoader implements a PSR-0, PSR-4 and classmap class loader.
*
* $loader = new \Composer\Autoload\ClassLoader();
*
* // register classes with namespaces
* $loader->add('Symfony\Component', __DIR__.'/component');
* $loader->add('Symfony', __DIR__.'/framework');
*
* // activate the autoloader
* $loader->register();
*
* // to enable searching the include path (eg. for PEAR packages)
* $loader->setUseIncludePath(true);
*
* In this example, if you try to use a class in the Symfony\Component
* namespace or one of its children (Symfony\Component\Console for instance),
* the autoloader will first look for the class under the component/
* directory, and it will then fallback to the framework/ directory if not
* found before giving up.
*
* This class is loosely based on the Symfony UniversalClassLoader.
*
* @author Fabien Potencier <fabien@symfony.com>
* @author Jordi Boggiano <j.boggiano@seld.be>
* @see http://www.php-fig.org/psr/psr-0/
* @see http://www.php-fig.org/psr/psr-4/
*/
class ClassLoader
{
// PSR-4
private $prefixLengthsPsr4 = array();
private $prefixDirsPsr4 = array();
private $fallbackDirsPsr4 = array();
// PSR-0
private $prefixesPsr0 = array();
private $fallbackDirsPsr0 = array();
private $useIncludePath = false;
private $classMap = array();
private $classMapAuthoritative = false;
private $missingClasses = array();
private $apcuPrefix;
public function getPrefixes()
{
if (!empty($this->prefixesPsr0)) {
return call_user_func_array('array_merge', array_values($this->prefixesPsr0));
}
return array();
}
public function getPrefixesPsr4()
{
return $this->prefixDirsPsr4;
}
public function getFallbackDirs()
{
return $this->fallbackDirsPsr0;
}
public function getFallbackDirsPsr4()
{
return $this->fallbackDirsPsr4;
}
public function getClassMap()
{
return $this->classMap;
}
/**
* @param array $classMap Class to filename map
*/
public function addClassMap(array $classMap)
{
if ($this->classMap) {
$this->classMap = array_merge($this->classMap, $classMap);
} else {
$this->classMap = $classMap;
}
}
/**
* Registers a set of PSR-0 directories for a given prefix, either
* appending or prepending to the ones previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 root directories
* @param bool $prepend Whether to prepend the directories
*/
public function add($prefix, $paths, $prepend = false)
{
if (!$prefix) {
if ($prepend) {
$this->fallbackDirsPsr0 = array_merge(
(array) $paths,
$this->fallbackDirsPsr0
);
} else {
$this->fallbackDirsPsr0 = array_merge(
$this->fallbackDirsPsr0,
(array) $paths
);
}
return;
}
$first = $prefix[0];
if (!isset($this->prefixesPsr0[$first][$prefix])) {
$this->prefixesPsr0[$first][$prefix] = (array) $paths;
return;
}
if ($prepend) {
$this->prefixesPsr0[$first][$prefix] = array_merge(
(array) $paths,
$this->prefixesPsr0[$first][$prefix]
);
} else {
$this->prefixesPsr0[$first][$prefix] = array_merge(
$this->prefixesPsr0[$first][$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-4 directories for a given namespace, either
* appending or prepending to the ones previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
* @param bool $prepend Whether to prepend the directories
*
* @throws \InvalidArgumentException
*/
public function addPsr4($prefix, $paths, $prepend = false)
{
if (!$prefix) {
// Register directories for the root namespace.
if ($prepend) {
$this->fallbackDirsPsr4 = array_merge(
(array) $paths,
$this->fallbackDirsPsr4
);
} else {
$this->fallbackDirsPsr4 = array_merge(
$this->fallbackDirsPsr4,
(array) $paths
);
}
} elseif (!isset($this->prefixDirsPsr4[$prefix])) {
// Register directories for a new namespace.
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
} elseif ($prepend) {
// Prepend directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
(array) $paths,
$this->prefixDirsPsr4[$prefix]
);
} else {
// Append directories for an already registered namespace.
$this->prefixDirsPsr4[$prefix] = array_merge(
$this->prefixDirsPsr4[$prefix],
(array) $paths
);
}
}
/**
* Registers a set of PSR-0 directories for a given prefix,
* replacing any others previously set for this prefix.
*
* @param string $prefix The prefix
* @param array|string $paths The PSR-0 base directories
*/
public function set($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr0 = (array) $paths;
} else {
$this->prefixesPsr0[$prefix[0]][$prefix] = (array) $paths;
}
}
/**
* Registers a set of PSR-4 directories for a given namespace,
* replacing any others previously set for this namespace.
*
* @param string $prefix The prefix/namespace, with trailing '\\'
* @param array|string $paths The PSR-4 base directories
*
* @throws \InvalidArgumentException
*/
public function setPsr4($prefix, $paths)
{
if (!$prefix) {
$this->fallbackDirsPsr4 = (array) $paths;
} else {
$length = strlen($prefix);
if ('\\' !== $prefix[$length - 1]) {
throw new \InvalidArgumentException("A non-empty PSR-4 prefix must end with a namespace separator.");
}
$this->prefixLengthsPsr4[$prefix[0]][$prefix] = $length;
$this->prefixDirsPsr4[$prefix] = (array) $paths;
}
}
/**
* Turns on searching the include path for class files.
*
* @param bool $useIncludePath
*/
public function setUseIncludePath($useIncludePath)
{
$this->useIncludePath = $useIncludePath;
}
/**
* Can be used to check if the autoloader uses the include path to check
* for classes.
*
* @return bool
*/
public function getUseIncludePath()
{
return $this->useIncludePath;
}
/**
* Turns off searching the prefix and fallback directories for classes
* that have not been registered with the class map.
*
* @param bool $classMapAuthoritative
*/
public function setClassMapAuthoritative($classMapAuthoritative)
{
$this->classMapAuthoritative = $classMapAuthoritative;
}
/**
* Should class lookup fail if not found in the current class map?
*
* @return bool
*/
public function isClassMapAuthoritative()
{
return $this->classMapAuthoritative;
}
/**
* APCu prefix to use to cache found/not-found classes, if the extension is enabled.
*
* @param string|null $apcuPrefix
*/
public function setApcuPrefix($apcuPrefix)
{
$this->apcuPrefix = function_exists('apcu_fetch') && filter_var(ini_get('apc.enabled'), FILTER_VALIDATE_BOOLEAN) ? $apcuPrefix : null;
}
/**
* The APCu prefix in use, or null if APCu caching is not enabled.
*
* @return string|null
*/
public function getApcuPrefix()
{
return $this->apcuPrefix;
}
/**
* Registers this instance as an autoloader.
*
* @param bool $prepend Whether to prepend the autoloader or not
*/
public function register($prepend = false)
{
spl_autoload_register(array($this, 'loadClass'), true, $prepend);
}
/**
* Unregisters this instance as an autoloader.
*/
public function unregister()
{
spl_autoload_unregister(array($this, 'loadClass'));
}
/**
* Loads the given class or interface.
*
* @param string $class The name of the class
* @return bool|null True if loaded, null otherwise
*/
public function loadClass($class)
{
if ($file = $this->findFile($class)) {
includeFile($file);
return true;
}
}
/**
* Finds the path to the file where the class is defined.
*
* @param string $class The name of the class
*
* @return string|false The path if found, false otherwise
*/
public function findFile($class)
{
// class map lookup
if (isset($this->classMap[$class])) {
return $this->classMap[$class];
}
if ($this->classMapAuthoritative || isset($this->missingClasses[$class])) {
return false;
}
if (null !== $this->apcuPrefix) {
$file = apcu_fetch($this->apcuPrefix.$class, $hit);
if ($hit) {
return $file;
}
}
$file = $this->findFileWithExtension($class, '.php');
// Search for Hack files if we are running on HHVM
if (false === $file && defined('HHVM_VERSION')) {
$file = $this->findFileWithExtension($class, '.hh');
}
if (null !== $this->apcuPrefix) {
apcu_add($this->apcuPrefix.$class, $file);
}
if (false === $file) {
// Remember that this class does not exist.
$this->missingClasses[$class] = true;
}
return $file;
}
private function findFileWithExtension($class, $ext)
{
// PSR-4 lookup
$logicalPathPsr4 = strtr($class, '\\', DIRECTORY_SEPARATOR) . $ext;
$first = $class[0];
if (isset($this->prefixLengthsPsr4[$first])) {
$subPath = $class;
while (false !== $lastPos = strrpos($subPath, '\\')) {
$subPath = substr($subPath, 0, $lastPos);
$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;
}
}
}
}
}
// PSR-4 fallback dirs
foreach ($this->fallbackDirsPsr4 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr4)) {
return $file;
}
}
// PSR-0 lookup
if (false !== $pos = strrpos($class, '\\')) {
// namespaced class name
$logicalPathPsr0 = substr($logicalPathPsr4, 0, $pos + 1)
. strtr(substr($logicalPathPsr4, $pos + 1), '_', DIRECTORY_SEPARATOR);
} else {
// PEAR-like class name
$logicalPathPsr0 = strtr($class, '_', DIRECTORY_SEPARATOR) . $ext;
}
if (isset($this->prefixesPsr0[$first])) {
foreach ($this->prefixesPsr0[$first] as $prefix => $dirs) {
if (0 === strpos($class, $prefix)) {
foreach ($dirs as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
}
}
}
// PSR-0 fallback dirs
foreach ($this->fallbackDirsPsr0 as $dir) {
if (file_exists($file = $dir . DIRECTORY_SEPARATOR . $logicalPathPsr0)) {
return $file;
}
}
// PSR-0 include paths.
if ($this->useIncludePath && $file = stream_resolve_include_path($logicalPathPsr0)) {
return $file;
}
return false;
}
}
/**
* Scope isolated include.
*
* Prevents access to $this/self from included files.
*/
function includeFile($file)
{
include $file;
}
+21
View File
@@ -0,0 +1,21 @@
Copyright (c) Nils Adermann, Jordi Boggiano
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.
+9
View File
@@ -0,0 +1,9 @@
<?php
// autoload_classmap.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);
+11
View File
@@ -0,0 +1,11 @@
<?php
// autoload_namespaces.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
'Gregwar\\Image' => array($vendorDir . '/gregwar/image'),
'Gregwar\\Cache' => array($vendorDir . '/gregwar/cache'),
);
+9
View File
@@ -0,0 +1,9 @@
<?php
// autoload_psr4.php @generated by Composer
$vendorDir = dirname(dirname(__FILE__));
$baseDir = dirname($vendorDir);
return array(
);
+55
View File
@@ -0,0 +1,55 @@
<?php
// autoload_real.php @generated by Composer
class ComposerAutoloaderInitd0872984a1db7aa104ae1184a3170d3e
{
private static $loader;
public static function loadClassLoader($class)
{
if ('Composer\Autoload\ClassLoader' === $class) {
require __DIR__ . '/ClassLoader.php';
}
}
/**
* @return \Composer\Autoload\ClassLoader
*/
public static function getLoader()
{
if (null !== self::$loader) {
return self::$loader;
}
spl_autoload_register(array('ComposerAutoloaderInitd0872984a1db7aa104ae1184a3170d3e', 'loadClassLoader'), true, true);
self::$loader = $loader = new \Composer\Autoload\ClassLoader();
spl_autoload_unregister(array('ComposerAutoloaderInitd0872984a1db7aa104ae1184a3170d3e', 'loadClassLoader'));
$useStaticLoader = PHP_VERSION_ID >= 50600 && !defined('HHVM_VERSION') && (!function_exists('zend_loader_file_encoded') || !zend_loader_file_encoded());
if ($useStaticLoader) {
require_once __DIR__ . '/autoload_static.php';
call_user_func(\Composer\Autoload\ComposerStaticInitd0872984a1db7aa104ae1184a3170d3e::getInitializer($loader));
} else {
$map = require __DIR__ . '/autoload_namespaces.php';
foreach ($map as $namespace => $path) {
$loader->set($namespace, $path);
}
$map = require __DIR__ . '/autoload_psr4.php';
foreach ($map as $namespace => $path) {
$loader->setPsr4($namespace, $path);
}
$classMap = require __DIR__ . '/autoload_classmap.php';
if ($classMap) {
$loader->addClassMap($classMap);
}
}
$loader->register(true);
return $loader;
}
}
+30
View File
@@ -0,0 +1,30 @@
<?php
// autoload_static.php @generated by Composer
namespace Composer\Autoload;
class ComposerStaticInitd0872984a1db7aa104ae1184a3170d3e
{
public static $prefixesPsr0 = array (
'G' =>
array (
'Gregwar\\Image' =>
array (
0 => __DIR__ . '/..' . '/gregwar/image',
),
'Gregwar\\Cache' =>
array (
0 => __DIR__ . '/..' . '/gregwar/cache',
),
),
);
public static function getInitializer(ClassLoader $loader)
{
return \Closure::bind(function () use ($loader) {
$loader->prefixesPsr0 = ComposerStaticInitd0872984a1db7aa104ae1184a3170d3e::$prefixesPsr0;
}, null, ClassLoader::class);
}
}
+113
View File
@@ -0,0 +1,113 @@
[
{
"name": "gregwar/cache",
"version": "v1.0.13",
"version_normalized": "1.0.13.0",
"target-dir": "Gregwar/Cache",
"source": {
"type": "git",
"url": "https://github.com/Gregwar/Cache.git",
"reference": "184cc341c25298ff7d584f86b55b6ca26626da4f"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Gregwar/Cache/zipball/184cc341c25298ff7d584f86b55b6ca26626da4f",
"reference": "184cc341c25298ff7d584f86b55b6ca26626da4f",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"php": ">=5.3"
},
"time": "2021-04-20T07:23:58+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"Gregwar\\Cache": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Gregwar",
"email": "g.passault@gmail.com"
}
],
"description": "A lightweight file-system cache system",
"keywords": [
"cache",
"caching",
"file-system",
"system"
]
},
{
"name": "gregwar/image",
"version": "v2.1.0",
"version_normalized": "2.1.0.0",
"target-dir": "Gregwar/Image",
"source": {
"type": "git",
"url": "https://github.com/Gregwar/Image.git",
"reference": "1cf64c34cbb22933b36727c16b15ed4d925b6fc6"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Gregwar/Image/zipball/1cf64c34cbb22933b36727c16b15ed4d925b6fc6",
"reference": "1cf64c34cbb22933b36727c16b15ed4d925b6fc6",
"shasum": "",
"mirrors": [
{
"url": "https://mirrors.aliyun.com/composer/dists/%package%/%reference%.%type%",
"preferred": true
}
]
},
"require": {
"ext-gd": "*",
"gregwar/cache": "^1.0.6",
"php": "^5.6 || ^7.0 || ^8.0"
},
"require-dev": {
"sllh/php-cs-fixer-styleci-bridge": "~1.0",
"symfony/phpunit-bridge": "^2.7.4 || ^3.0"
},
"suggest": {
"behat/transliterator": "Transliterator provides ability to set non-latin1 pretty names"
},
"time": "2021-02-17T16:00:53+00:00",
"type": "library",
"installation-source": "dist",
"autoload": {
"psr-0": {
"Gregwar\\Image": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Grégoire Passault",
"email": "g.passault@gmail.com",
"homepage": "http://www.gregwar.com/"
}
],
"description": "Image handling",
"homepage": "https://github.com/Gregwar/Image",
"keywords": [
"gd",
"image"
]
}
]
@@ -0,0 +1,3 @@
**.swp
vendor
composer.lock
+11
View File
@@ -0,0 +1,11 @@
language: php
php:
- 7.3
- 8.0
script:
- composer install
- mkdir tests/cache
- chmod 777 tests/cache
- phpunit
+366
View File
@@ -0,0 +1,366 @@
<?php
namespace Gregwar\Cache;
/**
* A cache system based on files
*
* @author Gregwar <g.passault@gmail.com>
*/
class Cache implements CacheInterface
{
/**
* Cache directory
* @var string
*/
protected $cacheDirectory;
/**
* Use a different directory as actual cache
* @var string|null
*/
protected $actualCacheDirectory;
/**
* Prefix directories size
*
* For instance, if the file is helloworld.txt and the prefix size is
* 5, the cache file will be: h/e/l/l/o/helloworld.txt
*
* This is useful to avoid reaching a too large number of files into the
* cache system directories
* @var int
*/
protected $prefixSize = 5;
/**
* Directory mode
*
* Allows setting of the access mode for the directories created.
* @var int
*/
protected $directoryMode = 0755;
/**
* Constructs the cache system
*
* @param string $cacheDirectory the cache directory
*/
public function __construct($cacheDirectory = 'cache')
{
$this->cacheDirectory = $cacheDirectory;
}
/**
* Sets the cache directory
*
* @param string $cacheDirectory the cache directory
* @return self
*/
public function setCacheDirectory($cacheDirectory)
{
$this->cacheDirectory = $cacheDirectory;
return $this;
}
/**
* Gets the cache directory
*
* @return string the cache directory
*/
public function getCacheDirectory()
{
return $this->cacheDirectory;
}
/**
* Sets the actual cache directory
*
* @param string|null $actualCacheDirectory the actual cache directory
* @return self
*/
public function setActualCacheDirectory($actualCacheDirectory = null)
{
$this->actualCacheDirectory = $actualCacheDirectory;
return $this;
}
/**
* Returns the actual cache directory
*/
public function getActualCacheDirectory()
{
return $this->actualCacheDirectory ?: $this->cacheDirectory;
}
/**
* Change the prefix size
*
* @param int $prefixSize the size of the prefix directories
* @return self
*/
public function setPrefixSize($prefixSize)
{
$this->prefixSize = $prefixSize;
return $this;
}
/**
* Change the directory mode
*
* @param int $directoryMode the directory mode to use
* @return self
*/
public function setDirectoryMode($directoryMode)
{
if (!$directoryMode) {
$directoryMode = 0755;
}
$this->directoryMode = $directoryMode;
return $this;
}
/**
* Creates a directory
*
* @param string $directory the target directory
*/
protected function mkdir($directory)
{
if (!is_dir($directory)) {
@mkdir($directory, $this->directoryMode, true);
}
}
/**
* Gets the cache file name
*
* @param string $filename the name of the cache file
* @param bool $actual get the actual file or the public file
* @param bool $mkdir a boolean to enable/disable the construction of the
* cache file directory
* @return string
*/
public function getCacheFile($filename, $actual = false, $mkdir = false)
{
$path = array();
// Getting the length of the filename before the extension
$parts = explode('.', $filename);
$len = strlen($parts[0]);
for ($i=0; $i<min($len, $this->prefixSize); $i++) {
$path[] = $filename[$i];
}
$path = implode('/', $path);
if ($mkdir) {
$actualDir = $this->getActualCacheDirectory() . '/' . $path;
$this->mkdir($actualDir);
}
$path .= '/' . $filename;
if ($actual) {
return $this->getActualCacheDirectory() . '/' . $path;
} else {
return $this->getCacheDirectory() . '/' . $path;
}
}
/**
* Checks that the cache conditions are respected
*
* @param string $cacheFile the cache file
* @param array $conditions an array of conditions to check
* @return bool
* @throws \Exception
*/
protected function checkConditions($cacheFile, array $conditions = array())
{
// Implicit condition: the cache file should exist
if (!file_exists($cacheFile)) {
return false;
}
foreach ($conditions as $type => $value) {
switch ($type) {
case 'maxage':
case 'max-age':
// Return false if the file is older than $value
$age = time() - filemtime($cacheFile);
if ($age > $value) {
return false;
}
break;
case 'younger-than':
case 'youngerthan':
// Return false if the file is older than the file $value, or the files $value
$check = function($filename) use ($cacheFile) {
return !file_exists($filename) || filemtime($cacheFile) < filemtime($filename);
};
if (!is_array($value)) {
if (!$this->isRemote($value) && $check($value)) {
return false;
}
} else {
foreach ($value as $file) {
if (!$this->isRemote($file) && $check($file)) {
return false;
}
}
}
break;
default:
throw new \Exception('Cache condition '.$type.' not supported');
}
}
return true;
}
/**
* Checks if the target filename exists in the cache and if the conditions
* are respected
*
* @param string $filename the filename
* @param array $conditions the conditions to respect
* @return bool
*/
public function exists($filename, array $conditions = array())
{
$cacheFile = $this->getCacheFile($filename, true);
return $this->checkConditions($cacheFile, $conditions);
}
/**
* Alias for exists
*
* @param string $filename the filename
* @param array $conditions the conditions to respect
* @return bool
*/
public function check($filename, array $conditions = array())
{
return $this->exists($filename, $conditions);
}
/**
* Write data in the cache
*
* @param string $filename the name of the cache file
* @param string $contents the contents to store
* @return self
*/
public function set($filename, $contents = '')
{
$cacheFile = $this->getCacheFile($filename, true, true);
file_put_contents($cacheFile, $contents, \LOCK_EX);
return $this;
}
/**
* Alias for set()
*
* @param string $filename the name of the cache file
* @param string $contents the contents to store
* @return self
*/
public function write($filename, $contents = '')
{
return $this->set($filename, $contents);
}
/**
* Get data from the cache
*
* @param string $filename the cache file name
* @param array $conditions
* @return null|string
*/
public function get($filename, array $conditions = array())
{
if ($this->exists($filename, $conditions)) {
return file_get_contents($this->getCacheFile($filename, true));
} else {
return null;
}
}
/**
* Is this URL remote?
*
* @param string $file
* @return bool
*/
protected function isRemote($file)
{
if (preg_match('/^([a-z]+):\/\//', $file, $match)) {
return ($match[1] != 'file');
}
return false;
}
/**
* Get or create the cache entry
*
* @param string $filename the cache file name
* @param array $conditions an array of conditions about expiration
* @param \Closure $function the closure to call if the file does not exist
* @param bool $file returns the cache file or the file contents
* @param bool $actual returns the actual cache file
* @return string
* @throws \InvalidArgumentException
*/
public function getOrCreate($filename, array $conditions, $function, $file = false, $actual = false)
{
if (!is_callable($function)) {
throw new \InvalidArgumentException('The argument $function should be callable');
}
$cacheFile = $this->getCacheFile($filename, true, true);
$data = null;
if (!$this->check($filename, $conditions)) {
if(file_exists($cacheFile)) {
unlink($cacheFile);
}
$data = call_user_func($function, $cacheFile);
// Test if the closure wrote the file or if it returned the data
if (!file_exists($cacheFile)) {
$this->set($filename, $data);
} else {
$data = file_get_contents($cacheFile);
}
}
return $file ? $this->getCacheFile($filename, $actual) : file_get_contents($cacheFile);
}
/**
* Alias to getOrCreate with $file = true
*
* @param string $filename the cache file name
* @param array $conditions an array of conditions about expiration
* @param \Closure $function the closure to call if the file does not exist
* @param bool $actual returns the actual cache file
* @return string
* @throws \InvalidArgumentException
*/
public function getOrCreateFile($filename, array $conditions, $function, $actual = false)
{
return $this->getOrCreate($filename, $conditions, $function, true, $actual);
}
}
@@ -0,0 +1,131 @@
<?php namespace Gregwar\Cache;
interface CacheInterface {
/**
* Sets the cache directory
*
* @param string $cacheDirectory the cache directory
* @return self
*/
public function setCacheDirectory($cacheDirectory);
/**
* Gets the cache directory
*
* @return string the cache directory
*/
public function getCacheDirectory();
/**
* Sets the actual cache directory
*
* @param string|null $actualCacheDirectory the actual cache directory
* @return self
*/
public function setActualCacheDirectory($actualCacheDirectory = null);
/**
* Returns the actual cache directory
*/
public function getActualCacheDirectory();
/**
* Change the prefix size
*
* @param int $prefixSize the size of the prefix directories
* @return self
*/
public function setPrefixSize($prefixSize);
/**
* Change the directory mode
*
* @param int $directoryMode the directory mode to use
* @return self
*/
public function setDirectoryMode($directoryMode);
/**
* Gets the cache file name
*
* @param string $filename the name of the cache file
* @param bool $actual get the actual file or the public file
* @param bool $mkdir a boolean to enable/disable the construction of the
* cache file directory
* @return string
*/
public function getCacheFile($filename, $actual = false, $mkdir = false);
/**
* Checks if the target filename exists in the cache and if the conditions
* are respected
*
* @param string $filename the filename
* @param array $conditions the conditions to respect
* @return bool
*/
public function exists($filename, array $conditions = array());
/**
* Alias for exists
*
* @param string $filename the filename
* @param array $conditions the conditions to respect
* @return bool
*/
public function check($filename, array $conditions = array());
/**
* Write data in the cache
*
* @param string $filename the name of the cache file
* @param string $contents the contents to store
* @return self
*/
public function set($filename, $contents = '');
/**
* Alias for set()
*
* @param string $filename the name of the cache file
* @param string $contents the contents to store
* @return self
*/
public function write($filename, $contents = '');
/**
* Get data from the cache
*
* @param string $filename the cache file name
* @param array $conditions
* @return null|string
*/
public function get($filename, array $conditions = array());
/**
* Get or create the cache entry
*
* @param string $filename the cache file name
* @param array $conditions an array of conditions about expiration
* @param \Closure $function the closure to call if the file does not exist
* @param bool $file returns the cache file or the file contents
* @param bool $actual returns the actual cache file
* @return string
* @throws \InvalidArgumentException
*/
public function getOrCreate($filename, array $conditions, $function, $file = false, $actual = false);
/**
* Alias to getOrCreate with $file = true
*
* @param string $filename the cache file name
* @param array $conditions an array of conditions about expiration
* @param \Closure $function the closure to call if the file does not exist
* @param bool $actual returns the actual cache file
* @return string
* @throws \InvalidArgumentException
*/
public function getOrCreateFile($filename, array $conditions, $function, $actual = false);
}
@@ -0,0 +1,86 @@
<?php
namespace Gregwar\Cache;
/**
* Garbage collect a directory, this will crawl a directory, lookng
* for files older than X days and destroy them
*
* @author Gregwar <g.passault@gmail.com>
*/
class GarbageCollect
{
/**
* Drops old files of a directory
*
* @param string $directory the name of the target directory
* @param int $days the number of days to consider a file old
* @param bool $verbose enable verbose output
*
* @return bool true if all the files/directories of a directory was wiped
*/
public static function dropOldFiles($directory, $days = 30, $verbose = false)
{
$allDropped = true;
$now = time();
$dir = opendir($directory);
if (!$dir) {
if ($verbose) {
echo "! Unable to open $directory\n";
}
return false;
}
while ($file = readdir($dir)) {
if ($file == '.' || $file == '..') {
continue;
}
$fullName = $directory.'/'.$file;
$old = $now-filemtime($fullName);
if (is_dir($fullName)) {
// Directories are recursively crawled
if (static::dropOldFiles($fullName, $days, $verbose)) {
self::drop($fullName, $verbose);
} else {
$allDropped = false;
}
} else {
if ($old > (24*60*60*$days)) {
self::drop($fullName, $verbose);
} else {
$allDropped = false;
}
}
}
closedir($dir);
return $allDropped;
}
/**
* Drops a file or an empty directory
*
* @param string $file the file to be removed
* @param bool $verbose the verbosity
*/
public static function drop($file, $verbose = false)
{
if (is_dir($file)) {
@rmdir($file);
} else {
@unlink($file);
}
if ($verbose) {
echo "> Dropping $file...\n";
}
}
}
+19
View File
@@ -0,0 +1,19 @@
Copyright (c) <2013> Grégoire Passault
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.
+166
View File
@@ -0,0 +1,166 @@
Cache
=====
![Build status](https://travis-ci.org/Gregwar/Cache.svg?branch=master)
[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YUXRLWHQSWS6L)
This is a lightweight cache system based on file and directories.
Usage
=====
Step 1: Install it
------------------
Via composer:
```json
{
"require": {
"gregwar/cache": "1.0.*"
}
}
```
Or with a clone of the repository:
```bash
git clone https://github.com/Gregwar/Cache.git
```
Or downloading it:
* [Download .zip](https://github.com/Gregwar/Cache/archive/master.zip)
* [Download .tar.gz](https://github.com/Gregwar/Cache/archive/master.tar.gz)
Step 2: Setup the rights
------------------------
You need your PHP script to have access to the cache directory, you can for instance
create a `cache` directory (be sure the web server can write it):
```
mkdir cache
```
Step 3: Access the cache
------------------------
To access the cache, you can do like this:
```php
<?php
include('vendor/autoload.php'); // If using composer
use Gregwar\Cache\Cache;
$cache = new Cache;
$cache->setCacheDirectory('cache'); // This is the default
// If the cache exists, this will return it, else, the closure will be called
// to create this image
$data = $cache->getOrCreate('red-square.png', array(), function($filename) {
$i = imagecreatetruecolor(100, 100);
imagefill($i, 0, 0, 0xff0000);
imagepng($i, $filename);
});
header('Content-type: image/png');
echo $data;
```
This will render a red square. If the cache file (which will look like `cache/r/e/d/-/s/red-square.png')
exists, it will be read, else, the closure will be called in order to create the cache file.
API
===
You can use the following methods:
* `setCacheDirectory($directory)`: sets the cache directory (see below).
* `setActualCacheDirectory($directory)`: sets the actual cache directory (see below).
* `exists($filename, $conditions = array())`: check that the $filename file exists in the cache, checking
the conditions (see below).
* `check($filename, $conditions = array())`: alias for `exists`.
* `getCacheFile($filename, $actual = false, $mkdir = false)`: gets the cache file. If the `$actual` flag
is true, the actual cache file name will be returned (see below), if the `$mkdir` flag is true, the
cache file directories tree will be created.
* `set($filename, $contents)`: write contents to `$filename` cache file.
* `write($filename, $contents)`: alias for `set()`
* `get($filename, $conditions = array())`: if the cache file for `$filename` exists, contents will be
returned, else, `NULL` will be returned.
* `setPrefixSize($prefixSize)`: sets the prefix size for directories, default is 5. For instance, the
cache file for `helloworld.txt`, will be `'h/e/l/l/o/helloworld.txt`.
* `setDirectoryMode($directoryMode)`: sets the directory mode when creating directories, default is `0755`.
Does not affect any directories previously created.
* `getOrCreate($filename, $conditions = array(), $function, $file = false)`: this will check if the `$filename`
cache file exists and verifies `$conditions` (see below). If the cache file is OK, it will return its
contents. Else, it will call the `$function`, passing it the target file, this function can write the
file given in parameter or just return data. Then, cache data will be returned. If `$file` flag is set,
the cache file name will be returned instead of file data.
Note: consider using an hash for the `$filename` cache file, to avoid special characters.
Conditions
==========
You can use conditions to manage file expirations on the cache, there is two way of expiring:
* Using `max-age`, in seconds, to set the maximum age of the file
* Using `younger-than`, by passing another file, this will compare the modification date
and regenerate the cache if the given file is younger.
For instance, if you want to uppercase a file:
```php
<?php
use Gregwar\Cache\Cache;
$cache = new Cache;
$data = $cache->getOrCreate('uppercase.txt',
array(
'younger-than' => 'original.txt'
),
function() {
echo "Generating file...\n";
return strtoupper(file_get_contents('original.txt'));
});
echo $data;
```
This will be create the `uppercase.txt` cache file by uppercasing the `original.txt` if the cache file
does not exists or if the `original.txt` file is more recent than the cache file.
For instance:
```
php uppercase.php # Will generate the cache file
php uppercase.php # Will not generate the cache file
touch original.txt # Sets the last modification time to now
php uppercase.php # Will re-generate the cache file
```
Cache directory and actual cache directory
==========================================
In some cases, you'll want to get the cache file name. For instance, if you're caching
images, you'll want to give a string like `cache/s/o/m/e/i/someimage.png` to put it into
an `<img>` tag. This can be done by passing the `$file` argument to the `getOrCreate` to true,
or directly using `getCacheFile` method (see above).
However, the visible `cache` directory of your users is not the same as the absolute path
you want to access. To do that, you can set both the cache directory and the actual cache directory.
The cache directory is the prefix visible by the users (for instance: `cache/s/o/m/e/i/someimage.png`),
and the actual cache directory is the prefix to use to actually access to the image (for instance:
`/var/www/somesite/cache/s/o/m/e/i/someimage.png`). This way, the file will be accessed using absolute
path and the cache file returned will directly be usable for your user's browsers.
License
=======
This repository is under the MIT license, have a look at the `LICENCE` file.
+16
View File
@@ -0,0 +1,16 @@
<?php
/**
* Registers an autoload for all the classes in Gregwar\Cache
*/
spl_autoload_register(function ($className) {
$namespace = 'Gregwar\\Cache';
if (strpos($className, $namespace) === 0) {
$className = str_replace($namespace, '', $className);
$fileName = __DIR__ . '/' . str_replace('\\', '/', $className) . '.php';
if (file_exists($fileName)) {
require($fileName);
}
}
});
+21
View File
@@ -0,0 +1,21 @@
{
"name": "gregwar/cache",
"description": "A lightweight file-system cache system",
"keywords": ["cache", "caching", "system", "file-system"],
"license": "MIT",
"authors": [
{
"name": "Gregwar",
"email": "g.passault@gmail.com"
}
],
"target-dir": "Gregwar/Cache",
"require": {
"php": ">=5.3"
},
"autoload": {
"psr-0": {
"Gregwar\\Cache": ""
}
}
}
@@ -0,0 +1 @@
cache/
@@ -0,0 +1,14 @@
<?php
include('../autoload.php'); // If using composer
use Gregwar\Cache\GarbageCollect;
if (!is_dir('cache')) {
`mkdir cache`;
}
`touch -t 9901010101 cache/foo`;
`touch cache/bar`;
GarbageCollect::dropOldFiles(__DIR__.'/cache', 30, true);
@@ -0,0 +1,23 @@
<?php
include('../autoload.php');
$cache = new Gregwar\Cache\Cache;
$data = $cache->getOrCreate('uppercase.txt', array('max-age' => 2), function() {
echo "First call: generating file...\n";
return strtoupper(file_get_contents('original.txt'));
});
$data = $cache->getOrCreate('uppercase.txt', array('max-age' => 2), function() {
echo "Second call: generating file, this should not happen!...\n";
return strtoupper(file_get_contents('original.txt'));
});
echo "Waiting 4s...\n";
sleep(4);
$data = $cache->getOrCreate('uppercase.txt', array('max-age' => 2), function() {
echo "Third call: generating cache file, because it expired...\n";
return strtoupper(file_get_contents('original.txt'));
});
@@ -0,0 +1,4 @@
There he goes.
One of God's own prototypes.
A high-powered mutant of some kind never even considered for mass production.
Too weird to live, and too rare to die.
@@ -0,0 +1,20 @@
<?php
include('../autoload.php'); // If using composer
use Gregwar\Cache\Cache;
$cache = new Cache;
$cache->setCacheDirectory('cache'); // This is the default
// If the cache exists, this will return it, else, the closure will be called
// to create this image
$file = $cache->getOrCreateFile('red-square.png', array(), function($filename) {
$i = imagecreatetruecolor(100, 100);
imagefill($i, 0, 0, 0xff0000);
file_put_contents($filename, 'abc');
imagepng($i, 'a.png');
imagepng($i, $filename);
});
echo $file, "\n";
+20
View File
@@ -0,0 +1,20 @@
<?php
include('../autoload.php'); // If using composer
use Gregwar\Cache\Cache;
$cache = new Cache;
$cache->setCacheDirectory('cache'); // This is the default
// If the cache exists, this will return it, else, the closure will be called
// to create this image
$data = $cache->getOrCreate('red-square.png', array(), function($filename) {
$i = imagecreatetruecolor(100, 100);
imagefill($i, 0, 0, 0xff0000);
file_put_contents($filename, 'abc');
imagepng($i, $filename);
});
header('Content-type: image/png');
echo $data;
@@ -0,0 +1,14 @@
<?php
include('../autoload.php');
use Gregwar\Cache\Cache;
$cache = new Cache;
$data = $cache->getOrCreate('uppercase.txt', array('younger-than' => 'original.txt'), function() {
echo "Generating file...\n";
return strtoupper(file_get_contents('original.txt'));
});
echo $data;
+20
View File
@@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<phpunit backupGlobals="false"
backupStaticAttributes="false"
colors="true"
convertErrorsToExceptions="true"
convertNoticesToExceptions="true"
convertWarningsToExceptions="true"
processIsolation="false"
stopOnFailure="false"
syntaxCheck="false"
bootstrap="tests/bootstrap.php"
>
<testsuites>
<testsuite name="Cache testing">
<file>./tests/CacheTests.php</file>
</testsuite>
</testsuites>
</phpunit>
@@ -0,0 +1,208 @@
<?php
use Gregwar\Cache\Cache;
/**
* Unit testing for Cache
*/
class CacheTests extends \PHPUnit\Framework\TestCase
{
public function testContract()
{
$cache = $this->getCache();
$this->assertInstanceOf('Gregwar\Cache\CacheInterface', $cache);
}
/**
* Testing that file names are good
*/
public function testFileName()
{
$cache = $this->getCache();
$cacheDir = $this->getCacheDirectory();
$actualCacheDir = $this->getActualCacheDirectory();
$cacheFile = $cache->getCacheFile('helloworld.txt');
$actualCacheFile = $cache->getCacheFile('helloworld.txt', true);
$this->assertEquals($cacheDir . '/h/e/l/l/o/helloworld.txt', $cacheFile);
$this->assertEquals($actualCacheDir . '/h/e/l/l/o/helloworld.txt', $actualCacheFile);
$cacheFile = $cache->getCacheFile('xy.txt');
$actualCacheFile = $cache->getCacheFile('xy.txt', true);
$this->assertEquals($cacheDir . '/x/y/xy.txt', $cacheFile);
$this->assertEquals($actualCacheDir . '/x/y/xy.txt', $actualCacheFile);
}
/**
* Testing caching a file
*/
public function testCaching()
{
$cache = $this->getCache();
$this->assertFalse($cache->exists('testing.txt'));
$cache->set('testing.txt', 'toto');
$this->assertTrue($cache->exists('testing.txt'));
$this->assertFalse($cache->exists('testing2.txt'));
$cache->write('testing2.txt', 'toto');
$this->assertTrue($cache->exists('testing2.txt'));
$this->assertFalse($cache->exists('testing.txt', array(
'max-age' => -1
)));
$this->assertTrue($cache->exists('testing.txt', array(
'max-age' => 2
)));
sleep(3);
$this->assertFalse($cache->exists('testing.txt', array(
'max-age' => 2
)));
}
/**
* Testing the getOrCreate function
*/
public function testGetOrCreate()
{
$cache = $this->getCache();
$this->assertFalse($cache->exists('testing.txt'));
$data = $cache->getOrCreate('testing.txt', array(), function() {
return 'zebra';
});
$this->assertTrue($cache->exists('testing.txt'));
$this->assertEquals('zebra', $data);
$data = $cache->getOrCreate('testing.txt', array(), function() {
return 'elephant';
});
$this->assertEquals('zebra', $data);
}
/**
* Testing the getOrCreate function with a callable
*/
public function testGetOrCreateWithCallable()
{
$cache = $this->getCache();
$this->assertFalse($cache->exists('testing.txt'));
$data = $cache->getOrCreate('testing.txt', array(), array($this, 'getAnimal'));
$this->assertTrue($cache->exists('testing.txt'));
$this->assertEquals('orangutan', $data);
}
public function getAnimal()
{
return 'orangutan';
}
/**
* Testing the getOrCreate function with $file=true
*/
public function testGetOrCreateFile()
{
$dir = __DIR__;
$cache = $this->getCache();
$file = $dir.'/'.$cache->getOrCreateFile('file.txt', array(), function() {
return 'xyz';
});
$file2 = $dir.'/'.$cache->getOrCreate('file.txt', array(), function(){}, true);
$this->assertEquals($file, $file2);
$this->assertTrue(file_exists($file));
$this->assertEquals('xyz', file_get_contents($file));
}
/**
* Testing that the not existing younger file works
*/
public function testNotExistingYounger()
{
$cache = $this->getCache();
$data = $cache->getOrCreate('testing.txt', array('younger-than'=> 'i-dont-exist'), function() {
return 'some-data';
});
$this->assertEquals('some-data', $data);
}
/**
* Testing that directory mode works
*/
public function testDirectoryMode()
{
$dir = __DIR__;
$cache = $this->getCache();
$cacheDir = $this->getCacheDirectory();
// default permissions are 0755
$data = $cache->getOrCreate('aaa.txt', array(), function () {
return 'abc';
});
$this->assertTrue((fileperms("$dir/$cacheDir/a") & 0777) == 0755);
$this->assertTrue((fileperms("$dir/$cacheDir/a/a") & 0777) == 0755);
$this->assertTrue((fileperms("$dir/$cacheDir/a/a/a") & 0777) == 0755);
// Change permissions to be more restrictive
$cache->setDirectoryMode(0700);
$data = $cache->getOrCreate('bbb.txt', array(), function () {
return 'abc';
});
$this->assertTrue((fileperms("$dir/$cacheDir/b") & 0777) == 0700);
$this->assertTrue((fileperms("$dir/$cacheDir/b/b") & 0777) == 0700);
$this->assertTrue((fileperms("$dir/$cacheDir/b/b/b") & 0777) == 0700);
}
/**
* Testing that remotes does not cause cache regeneration
*/
public function testRemote()
{
$cache = $this->getCache();
$cache->set('remote', 'original');
$data = $cache->getOrCreate('remote', array('younger-than' => 'http://google.com'), function() {
return 'modified';
});
$data = $cache->getOrCreate('remote', array('younger-than' => 'ftps://google.com'), function() {
return 'modified';
});
$this->assertEquals('original', $data);
}
protected function getCache()
{
$cache = new Cache;
return $cache
->setPrefixSize(5)
->setCacheDirectory($this->getCacheDirectory())
->setActualCacheDirectory($this->getActualCacheDirectory())
;
}
protected function getActualCacheDirectory()
{
return __DIR__.'/'.$this->getCacheDirectory();
}
protected function getCacheDirectory()
{
return 'cache';
}
public function tearDown(): void
{
$cacheDirectory = $this->getActualCacheDirectory();
`rm -rf $cacheDirectory`;
}
}
@@ -0,0 +1,3 @@
<?php
include(__DIR__ . '/../autoload.php');
+12
View File
@@ -0,0 +1,12 @@
root = true
[*]
end_of_line = lf
insert_final_newline = true
[composer.json]
indent_style = space
indent_size = 4
[Makefile]
indent_style = tab
@@ -0,0 +1,7 @@
demo/cache
demo/out.jpg
**.swp
vendor
composer.lock
/phpunit.xml
/.php_cs.cache
+9
View File
@@ -0,0 +1,9 @@
<?php
require_once './vendor/autoload.php';
use SLLH\StyleCIBridge\ConfigBridge;
return ConfigBridge::create()
->setUsingCache(true)
;
+13
View File
@@ -0,0 +1,13 @@
preset: symfony
enabled:
- align_double_arrow
- newline_after_open_tag
- ordered_use
- long_array_syntax
- php_unit_construct
- php_unit_strict
disabled:
- unalign_double_arrow
- unalign_equals
+29
View File
@@ -0,0 +1,29 @@
language: php
php:
- 7.1
- 7.2
- 7.3
- 7.4
- 8.0
env:
global:
- PATH="$HOME/.composer/vendor/bin:$PATH"
matrix:
fast_finish: true
sudo: false
cache:
directories:
- $HOME/.composer/cache/files
before_script:
- composer selfupdate
- composer global require phpunit/phpunit --no-update
- composer global update --prefer-dist --no-interaction
- composer update --prefer-dist --no-interaction $COMPOSER_FLAGS
script: make test
@@ -0,0 +1,58 @@
<?php
namespace Gregwar\Image\Adapter;
use Gregwar\Image\Source\Source;
/**
* Base Adapter Implementation to handle Image information.
*/
abstract class Adapter implements AdapterInterface
{
/**
* @var Source
*/
protected $source;
/**
* The image resource handler.
*/
protected $resource;
public function __construct()
{
}
/**
* {@inheritdoc}
*/
public function setSource(Source $source)
{
$this->source = $source;
return $this;
}
/**
* {@inheritdoc}
*/
public function getResource()
{
return $this->resource;
}
/**
* Does this adapter supports the given type ?
*/
protected function supports($type)
{
return false;
}
/**
* Converts the image to true color.
*/
protected function convertToTrueColor()
{
}
}
@@ -0,0 +1,399 @@
<?php
namespace Gregwar\Image\Adapter;
use Gregwar\Image\Image;
use Gregwar\Image\Source\Source;
/**
* all the functions / methods to work on images.
*
* if changing anything please also add it to \Gregwar\Image\Image
*
* @author wodka <michael.schramm@gmail.com>
*/
interface AdapterInterface
{
/**
* set the image source for the adapter.
*
* @param Source $source
*
* @return $this
*/
public function setSource(Source $source);
/**
* get the raw resource.
*
* @return resource
*/
public function getResource();
/**
* Gets the name of the adapter.
*
* @return string
*/
public function getName();
/**
* Image width.
*
* @return int
*/
public function width();
/**
* Image height.
*
* @return int
*/
public function height();
/**
* Init the resource.
*
* @return $this
*/
public function init();
/**
* Unload the resource
*/
public function deinit();
/**
* Save the image as a gif.
*
* @return $this
*/
public function saveGif($file);
/**
* Save the image as a png.
*
* @return $this
*/
public function savePng($file);
/**
* Save the image as a Webp.
*
* @return $this
*/
public function saveWebp($file, $quality);
/**
* Save the image as a jpeg.
*
* @return $this
*/
public function saveJpeg($file, $quality);
/**
* Works as resize() excepts that the layout will be cropped.
*
* @param int $width the width
* @param int $height the height
* @param int $background the background
*
* @return $this
*/
public function cropResize($width = null, $height = null, $background = 0xffffff);
/**
* Resize the image preserving scale. Can enlarge it.
*
* @param int $width the width
* @param int $height the height
* @param int $background the background
* @param bool $crop
*
* @return $this
*/
public function scaleResize($width = null, $height = null, $background = 0xffffff, $crop = false);
/**
* Resizes the image. It will never be enlarged.
*
* @param int $width the width
* @param int $height the height
* @param int $background the background
* @param bool $force
* @param bool $rescale
* @param bool $crop
*
* @return $this
*/
public function resize($width = null, $height = null, $background = 0xffffff, $force = false, $rescale = false, $crop = false);
/**
* Crops the image.
*
* @param int $x the top-left x position of the crop box
* @param int $y the top-left y position of the crop box
* @param int $width the width of the crop box
* @param int $height the height of the crop box
*
* @return $this
*/
public function crop($x, $y, $width, $height);
/**
* enable progressive image loading.
*
* @return $this
*/
public function enableProgressive();
/**
* Resizes the image forcing the destination to have exactly the
* given width and the height.
*
* @param int $width the width
* @param int $height the height
* @param int $background the background
*
* @return $this
*/
public function forceResize($width = null, $height = null, $background = 0xffffff);
/**
* Perform a zoom crop of the image to desired width and height.
*
* @param int $width Desired width
* @param int $height Desired height
* @param int $background
*
* @return $this
*/
public function zoomCrop($width, $height, $background = 0xffffff);
/**
* Fills the image background to $bg if the image is transparent.
*
* @param int $background background color
*
* @return $this
*/
public function fillBackground($background = 0xffffff);
/**
* Negates the image.
*
* @return $this
*/
public function negate();
/**
* Changes the brightness of the image.
*
* @param int $brightness the brightness
*
* @return $this
*/
public function brightness($brightness);
/**
* Contrasts the image.
*
* @param int $contrast the contrast [-100, 100]
*
* @return $this
*/
public function contrast($contrast);
/**
* Apply a grayscale level effect on the image.
*
* @return $this
*/
public function grayscale();
/**
* Emboss the image.
*
* @return $this
*/
public function emboss();
/**
* Smooth the image.
*
* @param int $p value between [-10,10]
*
* @return $this
*/
public function smooth($p);
/**
* Sharps the image.
*
* @return $this
*/
public function sharp();
/**
* Edges the image.
*
* @return $this
*/
public function edge();
/**
* Colorize the image.
*
* @param int $red value in range [-255, 255]
* @param int $green value in range [-255, 255]
* @param int $blue value in range [-255, 255]
*
* @return $this
*/
public function colorize($red, $green, $blue);
/**
* apply sepia to the image.
*
* @return $this
*/
public function sepia();
/**
* Merge with another image.
*
* @param Image $other
* @param int $x
* @param int $y
* @param int $width
* @param int $height
*
* @return $this
*/
public function merge(Image $other, $x = 0, $y = 0, $width = null, $height = null);
/**
* Rotate the image.
*
* @param float $angle
* @param int $background
*
* @return $this
*/
public function rotate($angle, $background = 0xffffff);
/**
* Fills the image.
*
* @param int $color
* @param int $x
* @param int $y
*
* @return $this
*/
public function fill($color = 0xffffff, $x = 0, $y = 0);
/**
* write text to the image.
*
* @param string $font
* @param string $text
* @param int $x
* @param int $y
* @param int $size
* @param int $angle
* @param int $color
* @param string $align
*/
public function write($font, $text, $x = 0, $y = 0, $size = 12, $angle = 0, $color = 0x000000, $align = 'left');
/**
* Draws a rectangle.
*
* @param int $x1
* @param int $y1
* @param int $x2
* @param int $y2
* @param int $color
* @param bool $filled
*
* @return $this
*/
public function rectangle($x1, $y1, $x2, $y2, $color, $filled = false);
/**
* Draws a rounded rectangle.
*
* @param int $x1
* @param int $y1
* @param int $x2
* @param int $y2
* @param int $radius
* @param int $color
* @param bool $filled
*
* @return $this
*/
public function roundedRectangle($x1, $y1, $x2, $y2, $radius, $color, $filled = false);
/**
* Draws a line.
*
* @param int $x1
* @param int $y1
* @param int $x2
* @param int $y2
* @param int $color
*
* @return $this
*/
public function line($x1, $y1, $x2, $y2, $color = 0x000000);
/**
* Draws an ellipse.
*
* @param int $cx
* @param int $cy
* @param int $width
* @param int $height
* @param int $color
* @param bool $filled
*
* @return $this
*/
public function ellipse($cx, $cy, $width, $height, $color = 0x000000, $filled = false);
/**
* Draws a circle.
*
* @param int $cx
* @param int $cy
* @param int $r
* @param int $color
* @param bool $filled
*
* @return $this
*/
public function circle($cx, $cy, $r, $color = 0x000000, $filled = false);
/**
* Draws a polygon.
*
* @param array $points
* @param int $color
* @param bool $filled
*
* @return $this
*/
public function polygon(array $points, $color, $filled = false);
/**
* Flips the image.
*
* @param int $flipVertical
* @param int $flipHorizontal
*
* @return $this
*/
public function flip($flipVertical, $flipHorizontal);
}
@@ -0,0 +1,417 @@
<?php
namespace Gregwar\Image\Adapter;
abstract class Common extends Adapter
{
/**
* {@inheritdoc}
*/
public function zoomCrop($width, $height, $background = 'transparent', $xPosLetter = 'center', $yPosLetter = 'center')
{
$originalWidth = $this->width();
$originalHeight = $this->height();
// Calculate the different ratios
$originalRatio = $originalWidth / $originalHeight;
$newRatio = $width / $height;
// Compare ratios
if ($originalRatio > $newRatio) {
// Original image is wider
$newHeight = $height;
$newWidth = (int) $height * $originalRatio;
} else {
// Equal width or smaller
$newHeight = (int) $width / $originalRatio;
$newWidth = $width;
}
// Perform resize
$this->resize($newWidth, $newHeight, $background, true);
// Define x position
switch ($xPosLetter) {
case 'L':
case 'left':
$xPos = 0;
break;
case 'R':
case 'right':
$xPos = (int) $newWidth - $width;
break;
case 'center':
$xPos = (int) ($newWidth - $width) / 2;
break;
default:
$factorW = $newWidth / $originalWidth;
$xPos = $xPosLetter * $factorW;
// If the desired cropping position goes beyond the width then
// set the crop to be within the correct bounds.
if ($xPos + $width > $newWidth) {
$xPos = (int) $newWidth - $width;
}
}
// Define y position
switch ($yPosLetter) {
case 'T':
case 'top':
$yPos = 0;
break;
case 'B':
case 'bottom':
$yPos = (int) $newHeight - $height;
break;
case 'center':
$yPos = (int) ($newHeight - $height) / 2;
break;
default:
$factorH = $newHeight / $originalHeight;
$yPos = $yPosLetter * $factorH;
// If the desired cropping position goes beyond the height then
// set the crop to be within the correct bounds.
if ($yPos + $height > $newHeight) {
$yPos = (int) $newHeight - $height;
}
}
// Crop image to reach desired size
$this->crop($xPos, $yPos, $width, $height);
return $this;
}
/**
* Resizes the image forcing the destination to have exactly the
* given width and the height.
*
* @param int $w the width
* @param int $h the height
* @param int $bg the background
*/
public function forceResize($width = null, $height = null, $background = 'transparent')
{
return $this->resize($width, $height, $background, true);
}
/**
* {@inheritdoc}
*/
public function scaleResize($width = null, $height = null, $background = 'transparent', $crop = false)
{
return $this->resize($width, $height, $background, false, true, $crop);
}
/**
* {@inheritdoc}
*/
public function cropResize($width = null, $height = null, $background = 'transparent')
{
return $this->resize($width, $height, $background, false, false, true);
}
/**
* Read exif rotation from file and apply it.
*/
public function fixOrientation()
{
if (!in_array(exif_imagetype($this->source->getInfos()), array(
IMAGETYPE_JPEG,
IMAGETYPE_TIFF_II,
IMAGETYPE_TIFF_MM,
))) {
return $this;
}
if (!extension_loaded('exif')) {
throw new \RuntimeException('You need to EXIF PHP Extension to use this function');
}
$exif = @exif_read_data($this->source->getInfos());
if ($exif === false || !array_key_exists('Orientation', $exif)) {
return $this;
}
return $this->applyExifOrientation($exif['Orientation']);
}
/**
* Apply orientation using Exif orientation value.
*/
public function applyExifOrientation($exif_orienation)
{
switch ($exif_orienation) {
case 1:
break;
case 2:
$this->flip(false, true);
break;
case 3: // 180 rotate left
$this->rotate(180);
break;
case 4: // vertical flip
$this->flip(true, false);
break;
case 5: // vertical flip + 90 rotate right
$this->flip(true, false);
$this->rotate(-90);
break;
case 6: // 90 rotate right
$this->rotate(-90);
break;
case 7: // horizontal flip + 90 rotate right
$this->flip(false, true);
$this->rotate(-90);
break;
case 8: // 90 rotate left
$this->rotate(90);
break;
}
return $this;
}
/**
* Opens the image.
*/
abstract protected function openGif($file);
abstract protected function openJpeg($file);
abstract protected function openPng($file);
abstract protected function openWebp($file);
/**
* Creates an image.
*/
abstract protected function createImage($width, $height);
/**
* Creating an image using $data.
*/
abstract protected function createImageFromData($data);
/**
* Loading image from $resource.
*/
protected function loadResource($resource)
{
$this->resource = $resource;
}
protected function loadFile($file, $type)
{
if (!$this->supports($type)) {
throw new \RuntimeException('Type '.$type.' is not supported by GD');
}
if ($type == 'jpeg') {
$this->openJpeg($file);
}
if ($type == 'gif') {
$this->openGif($file);
}
if ($type == 'png') {
$this->openPng($file);
}
if ($type == 'webp') {
$this->openWebp($file);
}
if (false === $this->resource) {
throw new \UnexpectedValueException('Unable to open file ('.$file.')');
} else {
$this->convertToTrueColor();
}
}
/**
* {@inheritdoc}
*/
public function init()
{
$source = $this->source;
if ($source instanceof \Gregwar\Image\Source\File) {
$this->loadFile($source->getFile(), $source->guessType());
} elseif ($source instanceof \Gregwar\Image\Source\Create) {
$this->createImage($source->getWidth(), $source->getHeight());
} elseif ($source instanceof \Gregwar\Image\Source\Data) {
$this->createImageFromData($source->getData());
} elseif ($source instanceof \Gregwar\Image\Source\Resource) {
$this->loadResource($source->getResource());
} else {
throw new \Exception('Unsupported image source type '.get_class($source));
}
return $this;
}
/**
* {@inheritdoc}
*/
public function deinit()
{
$this->resource = null;
}
/**
* {@inheritdoc}
*/
public function resize($width = null, $height = null, $background = 'transparent', $force = false, $rescale = false, $crop = false)
{
$current_width = $this->width();
$current_height = $this->height();
$new_width = 0;
$new_height = 0;
$scale = 1.0;
if ($height === null && preg_match('#^(.+)%$#mUsi', $width, $matches)) {
$width = round($current_width * ((float) $matches[1] / 100.0));
$height = round($current_height * ((float) $matches[1] / 100.0));
}
if (!$rescale && (!$force || $crop)) {
if ($width != null && $current_width > $width) {
$scale = $current_width / $width;
}
if ($height != null && $current_height > $height) {
if ($current_height / $height > $scale) {
$scale = $current_height / $height;
}
}
} else {
if ($width != null) {
$scale = $current_width / $width;
$new_width = $width;
}
if ($height != null) {
if ($width != null && $rescale) {
$scale = max($scale, $current_height / $height);
} else {
$scale = $current_height / $height;
}
$new_height = $height;
}
}
if (!$force || $width == null || $rescale) {
$new_width = round($current_width / $scale);
}
if (!$force || $height == null || $rescale) {
$new_height = round($current_height / $scale);
}
if ($width == null || $crop) {
$width = $new_width;
}
if ($height == null || $crop) {
$height = $new_height;
}
$this->doResize($background, $width, $height, $new_width, $new_height);
}
/**
* Trim background color arround the image.
*
* @param int $bg the background
*/
protected function _trimColor($background = 'transparent')
{
$width = $this->width();
$height = $this->height();
$b_top = 0;
$b_lft = 0;
$b_btm = $height - 1;
$b_rt = $width - 1;
//top
for (; $b_top < $height; ++$b_top) {
for ($x = 0; $x < $width; ++$x) {
if ($this->getColor($x, $b_top) != $background) {
break 2;
}
}
}
// bottom
for (; $b_btm >= 0; --$b_btm) {
for ($x = 0; $x < $width; ++$x) {
if ($this->getColor($x, $b_btm) != $background) {
break 2;
}
}
}
// left
for (; $b_lft < $width; ++$b_lft) {
for ($y = $b_top; $y <= $b_btm; ++$y) {
if ($this->getColor($b_lft, $y) != $background) {
break 2;
}
}
}
// right
for (; $b_rt >= 0; --$b_rt) {
for ($y = $b_top; $y <= $b_btm; ++$y) {
if ($this->getColor($b_rt, $y) != $background) {
break 2;
}
}
}
++$b_btm;
++$b_rt;
$this->crop($b_lft, $b_top, $b_rt - $b_lft, $b_btm - $b_top);
}
/**
* Resizes the image to an image having size of $target_width, $target_height, using
* $new_width and $new_height and padding with $bg color.
*/
abstract protected function doResize($bg, $target_width, $target_height, $new_width, $new_height);
/**
* Gets the color of the $x, $y pixel.
*/
abstract protected function getColor($x, $y);
/**
* {@inheritdoc}
*/
public function enableProgressive()
{
throw new \Exception('The Adapter '.$this->getName().' does not support Progressive Image loading');
}
/**
* This does nothing, but can be used to tag a ressource for instance (having a final image hash
* for the cache different depending on the tag)
*/
public function tag($tag)
{
}
}
+665
View File
@@ -0,0 +1,665 @@
<?php
namespace Gregwar\Image\Adapter;
use Gregwar\Image\Image;
use Gregwar\Image\ImageColor;
class GD extends Common
{
public static $gdTypes = array(
'jpeg' => \IMG_JPG,
'gif' => \IMG_GIF,
'png' => \IMG_PNG,
'webp' => \IMG_WEBP
);
protected function loadResource($resource)
{
parent::loadResource($resource);
imagesavealpha($this->resource, true);
}
/**
* Gets the width and the height for writing some text.
*/
public static function TTFBox($font, $text, $size, $angle = 0)
{
$box = imagettfbbox($size, $angle, $font, $text);
return array(
'width' => abs($box[2] - $box[0]),
'height' => abs($box[3] - $box[5]),
);
}
public function __construct()
{
parent::__construct();
if (!(extension_loaded('gd') && function_exists('gd_info'))) {
throw new \RuntimeException('You need to install GD PHP Extension to use this library');
}
}
/**
* {@inheritdoc}
*/
public function getName()
{
return 'GD';
}
/**
* {@inheritdoc}
*/
public function fillBackground($background = 0xffffff)
{
$w = $this->width();
$h = $this->height();
$n = imagecreatetruecolor($w, $h);
imagefill($n, 0, 0, ImageColor::gdAllocate($this->resource, $background));
imagecopyresampled($n, $this->resource, 0, 0, 0, 0, $w, $h, $w, $h);
imagedestroy($this->resource);
$this->resource = $n;
return $this;
}
/**
* Do the image resize.
*
* @return $this
*/
protected function doResize($bg, $target_width, $target_height, $new_width, $new_height)
{
$width = $this->width();
$height = $this->height();
$n = imagecreatetruecolor($target_width, $target_height);
if ($bg != 'transparent') {
imagefill($n, 0, 0, ImageColor::gdAllocate($this->resource, $bg));
} else {
imagealphablending($n, false);
$color = ImageColor::gdAllocate($this->resource, 'transparent');
imagefill($n, 0, 0, $color);
imagesavealpha($n, true);
}
imagecopyresampled($n, $this->resource, ($target_width - $new_width) / 2, ($target_height - $new_height) / 2, 0, 0, $new_width, $new_height, $width, $height);
imagedestroy($this->resource);
$this->resource = $n;
return $this;
}
/**
* {@inheritdoc}
*/
public function crop($x, $y, $width, $height)
{
$destination = imagecreatetruecolor($width, $height);
imagealphablending($destination, false);
imagesavealpha($destination, true);
imagecopy($destination, $this->resource, 0, 0, $x, $y, $this->width(), $this->height());
imagedestroy($this->resource);
$this->resource = $destination;
return $this;
}
/**
* {@inheritdoc}
*/
public function negate()
{
imagefilter($this->resource, IMG_FILTER_NEGATE);
return $this;
}
/**
* {@inheritdoc}
*/
public function brightness($brightness)
{
imagefilter($this->resource, IMG_FILTER_BRIGHTNESS, $brightness);
return $this;
}
/**
* {@inheritdoc}
*/
public function contrast($contrast)
{
imagefilter($this->resource, IMG_FILTER_CONTRAST, $contrast);
return $this;
}
/**
* {@inheritdoc}
*/
public function grayscale()
{
imagefilter($this->resource, IMG_FILTER_GRAYSCALE);
return $this;
}
/**
* {@inheritdoc}
*/
public function emboss()
{
imagefilter($this->resource, IMG_FILTER_EMBOSS);
return $this;
}
/**
* {@inheritdoc}
*/
public function smooth($p)
{
imagefilter($this->resource, IMG_FILTER_SMOOTH, $p);
return $this;
}
/**
* {@inheritdoc}
*/
public function sharp()
{
imagefilter($this->resource, IMG_FILTER_MEAN_REMOVAL);
return $this;
}
/**
* {@inheritdoc}
*/
public function edge()
{
imagefilter($this->resource, IMG_FILTER_EDGEDETECT);
return $this;
}
/**
* {@inheritdoc}
*/
public function colorize($red, $green, $blue)
{
imagefilter($this->resource, IMG_FILTER_COLORIZE, $red, $green, $blue);
return $this;
}
/**
* {@inheritdoc}
*/
public function sepia()
{
imagefilter($this->resource, IMG_FILTER_GRAYSCALE);
imagefilter($this->resource, IMG_FILTER_COLORIZE, 100, 50, 0);
return $this;
}
/**
* {@inheritdoc}
*/
public function gaussianBlur($blurFactor = 1)
{
$blurFactor = round($blurFactor); // blurFactor has to be an integer
$originalWidth = $this->width();
$originalHeight = $this->height();
$smallestWidth = ceil($originalWidth * pow(0.5, $blurFactor));
$smallestHeight = ceil($originalHeight * pow(0.5, $blurFactor));
// for the first run, the previous image is the original input
$prevImage = $this->resource;
$prevWidth = $originalWidth;
$prevHeight = $originalHeight;
// scale way down and gradually scale back up, blurring all the way
for ($i = 0; $i < $blurFactor; ++$i) {
// determine dimensions of next image
$nextWidth = $smallestWidth * pow(2, $i);
$nextHeight = $smallestHeight * pow(2, $i);
// resize previous image to next size
$nextImage = imagecreatetruecolor($nextWidth, $nextHeight);
imagecopyresized($nextImage, $prevImage, 0, 0, 0, 0,
$nextWidth, $nextHeight, $prevWidth, $prevHeight);
// apply blur filter
imagefilter($nextImage, IMG_FILTER_GAUSSIAN_BLUR);
// now the new image becomes the previous image for the next step
$prevImage = $nextImage;
$prevWidth = $nextWidth;
$prevHeight = $nextHeight;
}
// scale back to original size and blur one more time
imagecopyresized($this->resource, $nextImage,
0, 0, 0, 0, $originalWidth, $originalHeight, $nextWidth, $nextHeight);
imagefilter($this->resource, IMG_FILTER_GAUSSIAN_BLUR);
// clean up
imagedestroy($prevImage);
return $this;
}
/**
* {@inheritdoc}
*/
public function merge(Image $other, $x = 0, $y = 0, $width = null, $height = null)
{
$other = clone $other;
$other->init();
$other->applyOperations();
imagealphablending($this->resource, true);
if (null == $width) {
$width = $other->width();
}
if (null == $height) {
$height = $other->height();
}
imagecopyresampled($this->resource, $other->getAdapter()->getResource(), $x, $y, 0, 0, $width, $height, $width, $height);
return $this;
}
/**
* {@inheritdoc}
*/
public function rotate($angle, $background = 0xffffff)
{
$this->resource = imagerotate($this->resource, $angle, ImageColor::gdAllocate($this->resource, $background));
imagealphablending($this->resource, true);
imagesavealpha($this->resource, true);
return $this;
}
/**
* {@inheritdoc}
*/
public function fill($color = 0xffffff, $x = 0, $y = 0)
{
imagealphablending($this->resource, false);
imagefill($this->resource, $x, $y, ImageColor::gdAllocate($this->resource, $color));
return $this;
}
/**
* {@inheritdoc}
*/
public function write($font, $text, $x = 0, $y = 0, $size = 12, $angle = 0, $color = 0x000000, $align = 'left')
{
imagealphablending($this->resource, true);
if ($align != 'left') {
$sim_size = self::TTFBox($font, $text, $size, $angle);
if ($align == 'center') {
$x -= $sim_size['width'] / 2;
}
if ($align == 'right') {
$x -= $sim_size['width'];
}
}
imagettftext($this->resource, $size, $angle, $x, $y, ImageColor::gdAllocate($this->resource, $color), $font, $text);
return $this;
}
/**
* {@inheritdoc}
*/
public function rectangle($x1, $y1, $x2, $y2, $color, $filled = false)
{
if ($filled) {
imagefilledrectangle($this->resource, $x1, $y1, $x2, $y2, ImageColor::gdAllocate($this->resource, $color));
} else {
imagerectangle($this->resource, $x1, $y1, $x2, $y2, ImageColor::gdAllocate($this->resource, $color));
}
return $this;
}
/**
* {@inheritdoc}
*/
public function roundedRectangle($x1, $y1, $x2, $y2, $radius, $color, $filled = false)
{
if ($color) {
$color = ImageColor::gdAllocate($this->resource, $color);
}
if ($filled == true) {
imagefilledrectangle($this->resource, $x1 + $radius, $y1, $x2 - $radius, $y2, $color);
imagefilledrectangle($this->resource, $x1, $y1 + $radius, $x1 + $radius - 1, $y2 - $radius, $color);
imagefilledrectangle($this->resource, $x2 - $radius + 1, $y1 + $radius, $x2, $y2 - $radius, $color);
imagefilledarc($this->resource, $x1 + $radius, $y1 + $radius, $radius * 2, $radius * 2, 180, 270, $color, IMG_ARC_PIE);
imagefilledarc($this->resource, $x2 - $radius, $y1 + $radius, $radius * 2, $radius * 2, 270, 360, $color, IMG_ARC_PIE);
imagefilledarc($this->resource, $x1 + $radius, $y2 - $radius, $radius * 2, $radius * 2, 90, 180, $color, IMG_ARC_PIE);
imagefilledarc($this->resource, $x2 - $radius, $y2 - $radius, $radius * 2, $radius * 2, 360, 90, $color, IMG_ARC_PIE);
} else {
imageline($this->resource, $x1 + $radius, $y1, $x2 - $radius, $y1, $color);
imageline($this->resource, $x1 + $radius, $y2, $x2 - $radius, $y2, $color);
imageline($this->resource, $x1, $y1 + $radius, $x1, $y2 - $radius, $color);
imageline($this->resource, $x2, $y1 + $radius, $x2, $y2 - $radius, $color);
imagearc($this->resource, $x1 + $radius, $y1 + $radius, $radius * 2, $radius * 2, 180, 270, $color);
imagearc($this->resource, $x2 - $radius, $y1 + $radius, $radius * 2, $radius * 2, 270, 360, $color);
imagearc($this->resource, $x1 + $radius, $y2 - $radius, $radius * 2, $radius * 2, 90, 180, $color);
imagearc($this->resource, $x2 - $radius, $y2 - $radius, $radius * 2, $radius * 2, 360, 90, $color);
}
return $this;
}
/**
* {@inheritdoc}
*/
public function line($x1, $y1, $x2, $y2, $color = 0x000000)
{
imageline($this->resource, $x1, $y1, $x2, $y2, ImageColor::gdAllocate($this->resource, $color));
return $this;
}
/**
* {@inheritdoc}
*/
public function ellipse($cx, $cy, $width, $height, $color = 0x000000, $filled = false)
{
if ($filled) {
imagefilledellipse($this->resource, $cx, $cy, $width, $height, ImageColor::gdAllocate($this->resource, $color));
} else {
imageellipse($this->resource, $cx, $cy, $width, $height, ImageColor::gdAllocate($this->resource, $color));
}
return $this;
}
/**
* {@inheritdoc}
*/
public function circle($cx, $cy, $r, $color = 0x000000, $filled = false)
{
return $this->ellipse($cx, $cy, $r, $r, ImageColor::gdAllocate($this->resource, $color), $filled);
}
/**
* {@inheritdoc}
*/
public function polygon(array $points, $color, $filled = false)
{
if ($filled) {
imagefilledpolygon($this->resource, $points, count($points) / 2, ImageColor::gdAllocate($this->resource, $color));
} else {
imagepolygon($this->resource, $points, count($points) / 2, ImageColor::gdAllocate($this->resource, $color));
}
return $this;
}
/**
* {@inheritdoc}
*/
public function flip($flipVertical, $flipHorizontal)
{
if (!$flipVertical && !$flipHorizontal) {
return $this;
}
if (function_exists('imageflip')) {
if ($flipVertical && $flipHorizontal) {
$flipMode = \IMG_FLIP_BOTH;
} elseif ($flipVertical && !$flipHorizontal) {
$flipMode = \IMG_FLIP_VERTICAL;
} elseif (!$flipVertical && $flipHorizontal) {
$flipMode = \IMG_FLIP_HORIZONTAL;
}
imageflip($this->resource, $flipMode);
} else {
$width = $this->width();
$height = $this->height();
$src_x = 0;
$src_y = 0;
$src_width = $width;
$src_height = $height;
if ($flipVertical) {
$src_y = $height - 1;
$src_height = -$height;
}
if ($flipHorizontal) {
$src_x = $width - 1;
$src_width = -$width;
}
$imgdest = imagecreatetruecolor($width, $height);
imagealphablending($imgdest, false);
imagesavealpha($imgdest, true);
if (imagecopyresampled($imgdest, $this->resource, 0, 0, $src_x, $src_y, $width, $height, $src_width, $src_height)) {
imagedestroy($this->resource);
$this->resource = $imgdest;
}
}
return $this;
}
/**
* {@inheritdoc}
*/
public function width()
{
if (null === $this->resource) {
$this->init();
}
return imagesx($this->resource);
}
/**
* {@inheritdoc}
*/
public function height()
{
if (null === $this->resource) {
$this->init();
}
return imagesy($this->resource);
}
protected function createImage($width, $height)
{
$this->resource = imagecreatetruecolor($width, $height);
}
protected function createImageFromData($data)
{
$this->resource = @imagecreatefromstring($data);
}
/**
* Converts the image to true color.
*/
protected function convertToTrueColor()
{
if (!imageistruecolor($this->resource)) {
if (function_exists('imagepalettetotruecolor')) {
// Available in PHP 5.5
imagepalettetotruecolor($this->resource);
} else {
$transparentIndex = imagecolortransparent($this->resource);
$w = $this->width();
$h = $this->height();
$img = imagecreatetruecolor($w, $h);
imagecopy($img, $this->resource, 0, 0, 0, 0, $w, $h);
if ($transparentIndex != -1) {
$width = $this->width();
$height = $this->height();
imagealphablending($img, false);
imagesavealpha($img, true);
for ($x = 0; $x < $width; ++$x) {
for ($y = 0; $y < $height; ++$y) {
if (imagecolorat($this->resource, $x, $y) == $transparentIndex) {
imagesetpixel($img, $x, $y, 127 << 24);
}
}
}
}
$this->resource = $img;
}
}
imagesavealpha($this->resource, true);
}
/**
* {@inheritdoc}
*/
public function saveGif($file)
{
$transColor = imagecolorallocatealpha($this->resource, 255, 255, 255, 127);
imagecolortransparent($this->resource, $transColor);
imagegif($this->resource, $file);
return $this;
}
/**
* {@inheritdoc}
*/
public function savePng($file)
{
imagepng($this->resource, $file);
return $this;
}
/**
* {@inheritdoc}
*/
public function saveWebp($file, $quality)
{
imagewebp($this->resource, $file, $quality);
return $this;
}
/**
* {@inheritdoc}
*/
public function saveJpeg($file, $quality)
{
imagejpeg($this->resource, $file, $quality);
return $this;
}
/**
* Try to open the file using jpeg.
*/
protected function openJpeg($file)
{
if (file_exists($file) && filesize($file)) {
$this->resource = @imagecreatefromjpeg($file);
} else {
$this->resource = false;
}
}
/**
* Try to open the file using gif.
*/
protected function openGif($file)
{
if (file_exists($file) && filesize($file)) {
$this->resource = @imagecreatefromgif($file);
} else {
$this->resource = false;
}
}
/**
* Try to open the file using PNG.
*/
protected function openPng($file)
{
if (file_exists($file) && filesize($file)) {
$this->resource = @imagecreatefrompng($file);
} else {
$this->resource = false;
}
}
/**
* Try to open the file using WEBP.
*/
protected function openWebp($file)
{
if (file_exists($file) && filesize($file)) {
$this->resource = @imagecreatefromwebp($file);
} else {
$this->resource = false;
}
}
/**
* Does this adapter supports type ?
*/
protected function supports($type)
{
return imagetypes() & self::$gdTypes[$type];
}
protected function getColor($x, $y)
{
return imagecolorat($this->resource, $x, $y);
}
/**
* {@inheritdoc}
*/
public function enableProgressive()
{
imageinterlace($this->resource, 1);
return $this;
}
}
@@ -0,0 +1,432 @@
<?php
namespace Gregwar\Image\Adapter;
use Gregwar\Image\Image;
class Imagick extends Common
{
public function __construct()
{
throw new \Exception('Imagick is not supported right now');
}
/**
* Gets the name of the adapter.
*
* @return string
*/
public function getName()
{
return 'ImageMagick';
}
/**
* Image width.
*
* @return int
*/
public function width()
{
// TODO: Implement width() method.
}
/**
* Image height.
*
* @return int
*/
public function height()
{
// TODO: Implement height() method.
}
/**
* Save the image as a gif.
*
* @return $this
*/
public function saveGif($file)
{
// TODO: Implement saveGif() method.
}
/**
* Save the image as a png.
*
* @return $this
*/
public function savePng($file)
{
// TODO: Implement savePng() method.
}
/**
* Save the image as a jpeg.
*
* @return $this
*/
public function saveJpeg($file, $quality)
{
// TODO: Implement saveJpeg() method.
}
/**
* Crops the image.
*
* @param int $x the top-left x position of the crop box
* @param int $y the top-left y position of the crop box
* @param int $width the width of the crop box
* @param int $height the height of the crop box
*
* @return $this
*/
public function crop($x, $y, $width, $height)
{
// TODO: Implement crop() method.
}
/**
* Fills the image background to $bg if the image is transparent.
*
* @param int $background background color
*
* @return $this
*/
public function fillBackground($background = 0xffffff)
{
// TODO: Implement fillBackground() method.
}
/**
* Negates the image.
*
* @return $this
*/
public function negate()
{
// TODO: Implement negate() method.
}
/**
* Changes the brightness of the image.
*
* @param int $brightness the brightness
*
* @return $this
*/
public function brightness($brightness)
{
// TODO: Implement brightness() method.
}
/**
* Contrasts the image.
*
* @param int $contrast the contrast [-100, 100]
*
* @return $this
*/
public function contrast($contrast)
{
// TODO: Implement contrast() method.
}
/**
* Apply a grayscale level effect on the image.
*
* @return $this
*/
public function grayscale()
{
// TODO: Implement grayscale() method.
}
/**
* Emboss the image.
*
* @return $this
*/
public function emboss()
{
// TODO: Implement emboss() method.
}
/**
* Smooth the image.
*
* @param int $p value between [-10,10]
*
* @return $this
*/
public function smooth($p)
{
// TODO: Implement smooth() method.
}
/**
* Sharps the image.
*
* @return $this
*/
public function sharp()
{
// TODO: Implement sharp() method.
}
/**
* Edges the image.
*
* @return $this
*/
public function edge()
{
// TODO: Implement edge() method.
}
/**
* Colorize the image.
*
* @param int $red value in range [-255, 255]
* @param int $green value in range [-255, 255]
* @param int $blue value in range [-255, 255]
*
* @return $this
*/
public function colorize($red, $green, $blue)
{
// TODO: Implement colorize() method.
}
/**
* apply sepia to the image.
*
* @return $this
*/
public function sepia()
{
// TODO: Implement sepia() method.
}
/**
* Merge with another image.
*
* @param Image $other
* @param int $x
* @param int $y
* @param int $width
* @param int $height
*
* @return $this
*/
public function merge(Image $other, $x = 0, $y = 0, $width = null, $height = null)
{
// TODO: Implement merge() method.
}
/**
* Rotate the image.
*
* @param float $angle
* @param int $background
*
* @return $this
*/
public function rotate($angle, $background = 0xffffff)
{
// TODO: Implement rotate() method.
}
/**
* Fills the image.
*
* @param int $color
* @param int $x
* @param int $y
*
* @return $this
*/
public function fill($color = 0xffffff, $x = 0, $y = 0)
{
// TODO: Implement fill() method.
}
/**
* write text to the image.
*
* @param string $font
* @param string $text
* @param int $x
* @param int $y
* @param int $size
* @param int $angle
* @param int $color
* @param string $align
*/
public function write($font, $text, $x = 0, $y = 0, $size = 12, $angle = 0, $color = 0x000000, $align = 'left')
{
// TODO: Implement write() method.
}
/**
* Draws a rectangle.
*
* @param int $x1
* @param int $y1
* @param int $x2
* @param int $y2
* @param int $color
* @param bool $filled
*
* @return $this
*/
public function rectangle($x1, $y1, $x2, $y2, $color, $filled = false)
{
// TODO: Implement rectangle() method.
}
/**
* Draws a rounded rectangle.
*
* @param int $x1
* @param int $y1
* @param int $x2
* @param int $y2
* @param int $radius
* @param int $color
* @param bool $filled
*
* @return $this
*/
public function roundedRectangle($x1, $y1, $x2, $y2, $radius, $color, $filled = false)
{
// TODO: Implement roundedRectangle() method.
}
/**
* Draws a line.
*
* @param int $x1
* @param int $y1
* @param int $x2
* @param int $y2
* @param int $color
*
* @return $this
*/
public function line($x1, $y1, $x2, $y2, $color = 0x000000)
{
// TODO: Implement line() method.
}
/**
* Draws an ellipse.
*
* @param int $cx
* @param int $cy
* @param int $width
* @param int $height
* @param int $color
* @param bool $filled
*
* @return $this
*/
public function ellipse($cx, $cy, $width, $height, $color = 0x000000, $filled = false)
{
// TODO: Implement ellipse() method.
}
/**
* Draws a circle.
*
* @param int $cx
* @param int $cy
* @param int $r
* @param int $color
* @param bool $filled
*
* @return $this
*/
public function circle($cx, $cy, $r, $color = 0x000000, $filled = false)
{
// TODO: Implement circle() method.
}
/**
* Draws a polygon.
*
* @param array $points
* @param int $color
* @param bool $filled
*
* @return $this
*/
public function polygon(array $points, $color, $filled = false)
{
// TODO: Implement polygon() method.
}
/**
* {@inheritdoc}
*/
public function flip($flipVertical, $flipHorizontal)
{
// TODO: Implement flip method
}
/**
* Opens the image.
*/
protected function openGif($file)
{
// TODO: Implement openGif() method.
}
protected function openJpeg($file)
{
// TODO: Implement openJpeg() method.
}
protected function openPng($file)
{
// TODO: Implement openPng() method.
}
protected function openWebp($file)
{
// TODO: Implement openWebp() method.
}
/**
* Creates an image.
*/
protected function createImage($width, $height)
{
// TODO: Implement createImage() method.
}
/**
* Creating an image using $data.
*/
protected function createImageFromData($data)
{
// TODO: Implement createImageFromData() method.
}
/**
* Resizes the image to an image having size of $target_width, $target_height, using
* $new_width and $new_height and padding with $bg color.
*/
protected function doResize($bg, $target_width, $target_height, $new_width, $new_height)
{
// TODO: Implement doResize() method.
}
/**
* Gets the color of the $x, $y pixel.
*/
protected function getColor($x, $y)
{
// TODO: Implement getColor() method.
}
}
@@ -0,0 +1,16 @@
<?php
namespace Gregwar\Image\Exceptions;
class GenerationError extends \Exception
{
public function __construct($newNewFile)
{
$this->newNewFile = $newNewFile;
}
public function getNewFile()
{
return $this->newNewFile;
}
}
@@ -0,0 +1,82 @@
<?php
namespace Gregwar\Image;
/**
* Garbage collect a directory, this will crawl a directory, lookng
* for files older than X days and destroy them.
*
* @author Gregwar <g.passault@gmail.com>
*/
class GarbageCollect
{
/**
* Drops old files of a directory.
*
* @param string $directory the name of the target directory
* @param int $days the number of days to consider a file old
* @param bool $verbose enable verbose output
*
* @return true if all the files/directories of a directory was wiped
*/
public static function dropOldFiles($directory, $days = 30, $verbose = false)
{
$allDropped = true;
$now = time();
$dir = opendir($directory);
if (!$dir) {
if ($verbose) {
echo "! Unable to open $directory\n";
}
return false;
}
while ($file = readdir($dir)) {
if ($file == '.' || $file == '..') {
continue;
}
$fullName = $directory.'/'.$file;
$old = $now - filemtime($fullName);
if (is_dir($fullName)) {
// Directories are recursively crawled
if (static::dropOldFiles($fullName, $days, $verbose)) {
self::drop($fullName, $verbose);
} else {
$allDropped = false;
}
} else {
if ($old > (24 * 60 * 60 * $days)) {
self::drop($fullName, $verbose);
} else {
$allDropped = false;
}
}
}
closedir($dir);
return $allDropped;
}
/**
* Drops a file or an empty directory.
*/
public static function drop($file, $verbose = false)
{
if (is_dir($file)) {
@rmdir($file);
} else {
@unlink($file);
}
if ($verbose) {
echo "> Dropping $file...\n";
}
}
}
+796
View File
@@ -0,0 +1,796 @@
<?php
namespace Gregwar\Image;
use Gregwar\Cache\CacheInterface;
use Gregwar\Image\Adapter\AdapterInterface;
use Gregwar\Image\Exceptions\GenerationError;
/**
* Images handling class.
*
* @author Gregwar <g.passault@gmail.com>
*
* @method Image saveGif($file)
* @method Image savePng($file)
* @method Image saveJpeg($file, $quality)
* @method Image resize($width = null, $height = null, $background = 'transparent', $force = false, $rescale = false, $crop = false)
* @method Image forceResize($width = null, $height = null, $background = 'transparent')
* @method Image scaleResize($width = null, $height = null, $background = 'transparent', $crop = false)
* @method Image cropResize($width = null, $height = null, $background=0xffffff)
* @method Image scale($width = null, $height = null, $background=0xffffff, $crop = false)
* @method Image ($width = null, $height = null, $background = 0xffffff, $force = false, $rescale = false, $crop = false)
* @method Image crop($x, $y, $width, $height)
* @method Image enableProgressive()
* @method Image force($width = null, $height = null, $background = 0xffffff)
* @method Image zoomCrop($width, $height, $background = 0xffffff, $xPos, $yPos)
* @method Image fillBackground($background = 0xffffff)
* @method Image negate()
* @method Image brightness($brightness)
* @method Image contrast($contrast)
* @method Image grayscale()
* @method Image emboss()
* @method Image smooth($p)
* @method Image sharp()
* @method Image edge()
* @method Image colorize($red, $green, $blue)
* @method Image sepia()
* @method Image merge(Image $other, $x = 0, $y = 0, $width = null, $height = null)
* @method Image rotate($angle, $background = 0xffffff)
* @method Image fill($color = 0xffffff, $x = 0, $y = 0)
* @method Image write($font, $text, $x = 0, $y = 0, $size = 12, $angle = 0, $color = 0x000000, $align = 'left')
* @method Image rectangle($x1, $y1, $x2, $y2, $color, $filled = false)
* @method Image roundedRectangle($x1, $y1, $x2, $y2, $radius, $color, $filled = false)
* @method Image line($x1, $y1, $x2, $y2, $color = 0x000000)
* @method Image ellipse($cx, $cy, $width, $height, $color = 0x000000, $filled = false)
* @method Image circle($cx, $cy, $r, $color = 0x000000, $filled = false)
* @method Image polygon(array $points, $color, $filled = false)
* @method Image flip($flipVertical, $flipHorizontal)
*/
class Image
{
/**
* Directory to use for file caching.
*/
protected $cacheDir = 'cache/images';
/**
* Directory cache mode.
*/
protected $cacheMode = null;
/**
* Internal adapter.
*
* @var AdapterInterface
*/
protected $adapter = null;
/**
* Pretty name for the image.
*/
protected $prettyName = '';
protected $prettyPrefix;
/**
* Transformations hash.
*/
protected $hash = null;
/**
* The image source.
*/
protected $source = null;
/**
* Force image caching, even if there is no operation applied.
*/
protected $forceCache = true;
/**
* Supported types.
*/
public static $types = array(
'jpg' => 'jpeg',
'jpeg' => 'jpeg',
'webp' => 'webp',
'png' => 'png',
'gif' => 'gif',
);
/**
* Fallback image.
*/
protected $fallback;
/**
* Use fallback image.
*/
protected $useFallbackImage = true;
/**
* Cache system.
*
* @var \Gregwar\Cache\CacheInterface
*/
protected $cache;
/**
* Get the cache system.
*
* @return \Gregwar\Cache\CacheInterface
*/
public function getCacheSystem()
{
if (is_null($this->cache)) {
$this->cache = new \Gregwar\Cache\Cache();
$this->cache->setCacheDirectory($this->cacheDir);
}
return $this->cache;
}
/**
* Set the cache system.
*
* @param \Gregwar\Cache\CacheInterface $cache
*/
public function setCacheSystem(CacheInterface $cache)
{
$this->cache = $cache;
}
/**
* Change the caching directory.
*/
public function setCacheDir($cacheDir)
{
$this->getCacheSystem()->setCacheDirectory($cacheDir);
return $this;
}
/**
* @param int $dirMode
*/
public function setCacheDirMode($dirMode)
{
$this->cache->setDirectoryMode($dirMode);
}
/**
* Enable or disable to force cache even if the file is unchanged.
*/
public function setForceCache($forceCache = true)
{
$this->forceCache = $forceCache;
return $this;
}
/**
* The actual cache dir.
*/
public function setActualCacheDir($actualCacheDir)
{
$this->getCacheSystem()->setActualCacheDirectory($actualCacheDir);
return $this;
}
/**
* Sets the pretty name of the image.
*/
public function setPrettyName($name, $prefix = true)
{
if (empty($name)) {
return $this;
}
$this->prettyName = $this->urlize($name);
$this->prettyPrefix = $prefix;
return $this;
}
/**
* Urlizes the prettyName.
*/
protected function urlize($name)
{
$transliterator = '\Behat\Transliterator\Transliterator';
if (class_exists($transliterator)) {
$name = $transliterator::transliterate($name);
$name = $transliterator::urlize($name);
} else {
$name = strtolower($name);
$name = str_replace(' ', '-', $name);
$name = preg_replace('/([^a-z0-9\-]+)/m', '', $name);
}
return $name;
}
/**
* Operations array.
*/
protected $operations = array();
public function __construct($originalFile = null, $width = null, $height = null)
{
$this->setFallback(null);
if ($originalFile) {
$this->source = new Source\File($originalFile);
} else {
$this->source = new Source\Create($width, $height);
}
}
/**
* Sets the image data.
*/
public function setData($data)
{
$this->source = new Source\Data($data);
}
/**
* Sets the resource.
*/
public function setResource($resource)
{
$this->source = new Source\Resource($resource);
}
/**
* Use the fallback image or not.
*/
public function useFallback($useFallbackImage = true)
{
$this->useFallbackImage = $useFallbackImage;
return $this;
}
/**
* Sets the fallback image to use.
*/
public function setFallback($fallback = null)
{
if ($fallback === null) {
$this->fallback = __DIR__.'/images/error.jpg';
} else {
$this->fallback = $fallback;
}
return $this;
}
/**
* Gets the fallack image path.
*/
public function getFallback()
{
return $this->fallback;
}
/**
* Gets the fallback into the cache dir.
*/
public function getCacheFallback()
{
$fallback = $this->fallback;
return $this->getCacheSystem()->getOrCreateFile('fallback.jpg', array(), function ($target) use ($fallback) {
copy($fallback, $target);
});
}
/**
* @return AdapterInterface
*/
public function getAdapter()
{
if (null === $this->adapter) {
// Defaults to GD
$this->setAdapter('gd');
}
return $this->adapter;
}
public function setAdapter($adapter)
{
if ($adapter instanceof Adapter\Adapter) {
$this->adapter = $adapter;
} else {
if (is_string($adapter)) {
$adapter = strtolower($adapter);
switch ($adapter) {
case 'gd':
$this->adapter = new Adapter\GD();
break;
case 'imagemagick':
case 'imagick':
$this->adapter = new Adapter\Imagick();
break;
default:
throw new \Exception('Unknown adapter: '.$adapter);
break;
}
} else {
throw new \Exception('Unable to load the given adapter (not string or Adapter)');
}
}
$this->adapter->setSource($this->source);
}
/**
* Get the file path.
*
* @return mixed a string with the filen name, null if the image
* does not depends on a file
*/
public function getFilePath()
{
if ($this->source instanceof Source\File) {
return $this->source->getFile();
} else {
return;
}
}
/**
* Defines the file only after instantiation.
*
* @param string $originalFile the file path
*/
public function fromFile($originalFile)
{
$this->source = new Source\File($originalFile);
return $this;
}
/**
* Tells if the image is correct.
*/
public function correct()
{
return $this->source->correct();
}
/**
* Guess the file type.
*/
public function guessType()
{
return $this->source->guessType();
}
/**
* Adds an operation.
*/
protected function addOperation($method, $args)
{
$this->operations[] = array($method, $args);
}
/**
* Generic function.
*/
public function __call($methodName, $args)
{
$adapter = $this->getAdapter();
$reflection = new \ReflectionClass(get_class($adapter));
if ($reflection->hasMethod($methodName)) {
$method = $reflection->getMethod($methodName);
if ($method->getNumberOfRequiredParameters() > count($args)) {
throw new \InvalidArgumentException('Not enough arguments given for '.$methodName);
}
$this->addOperation($methodName, $args);
return $this;
}
throw new \BadFunctionCallException('Invalid method: '.$methodName);
}
/**
* Serialization of operations.
*/
public function serializeOperations()
{
$datas = array();
foreach ($this->operations as $operation) {
$method = $operation[0];
$args = $operation[1];
foreach ($args as &$arg) {
if ($arg instanceof self) {
$arg = $arg->getHash();
}
}
$datas[] = array($method, $args);
}
return serialize($datas);
}
/**
* Generates the hash.
*/
public function generateHash($type = 'guess', $quality = 80)
{
$inputInfos = $this->source->getInfos();
$datas = array(
$inputInfos,
$this->serializeOperations(),
$type,
$quality,
);
$this->hash = sha1(serialize($datas));
}
/**
* Gets the hash.
*/
public function getHash($type = 'guess', $quality = 80)
{
if (null === $this->hash) {
$this->generateHash($type, $quality);
}
return $this->hash;
}
/**
* Gets the cache file name and generate it if it does not exists.
* Note that if it exists, all the image computation process will
* not be done.
*
* @param string $type the image type
* @param int $quality the quality (for JPEG)
*/
public function cacheFile($type = 'jpg', $quality = 80, $actual = false)
{
if ($type == 'guess') {
$type = $this->guessType();
}
if (!count($this->operations) && $type == $this->guessType() && !$this->forceCache) {
return $this->getFilename($this->getFilePath());
}
// Computes the hash
$this->hash = $this->getHash($type, $quality);
// Generates the cache file
$cacheFile = '';
if (!$this->prettyName || $this->prettyPrefix) {
$cacheFile .= $this->hash;
}
if ($this->prettyPrefix) {
$cacheFile .= '-';
}
if ($this->prettyName) {
$cacheFile .= $this->prettyName;
}
$cacheFile .= '.'.$type;
// If the files does not exists, save it
$image = $this;
// Target file should be younger than all the current image
// dependencies
$conditions = array(
'younger-than' => $this->getDependencies(),
);
// The generating function
$generate = function ($target) use ($image, $type, $quality) {
$result = $image->save($target, $type, $quality);
if ($result != $target) {
throw new GenerationError($result);
}
};
// Asking the cache for the cacheFile
try {
$file = $this->getCacheSystem()->getOrCreateFile($cacheFile, $conditions, $generate, $actual);
} catch (GenerationError $e) {
$file = $e->getNewFile();
}
// Nulling the resource
$this->getAdapter()->setSource(new Source\File($file));
$this->getAdapter()->deinit();
if ($actual) {
return $file;
} else {
return $this->getFilename($file);
}
}
/**
* Get cache data (to render the image).
*
* @param string $type the image type
* @param int $quality the quality (for JPEG)
*/
public function cacheData($type = 'jpg', $quality = 80)
{
return file_get_contents($this->cacheFile($type, $quality));
}
/**
* Hook to helps to extends and enhance this class.
*/
protected function getFilename($filename)
{
return $filename;
}
/**
* Generates and output a jpeg cached file.
*/
public function jpeg($quality = 80)
{
return $this->cacheFile('jpg', $quality);
}
/**
* Generates and output a gif cached file.
*/
public function gif()
{
return $this->cacheFile('gif');
}
/**
* Generates and output a png cached file.
*/
public function png()
{
return $this->cacheFile('png');
}
/**
* Generates and output a webp cached file.
*/
public function webp($quality = 80)
{
return $this->cacheFile('webp', $quality);
}
/**
* Generates and output an image using the same type as input.
*/
public function guess($quality = 80)
{
return $this->cacheFile('guess', $quality);
}
/**
* Get all the files that this image depends on.
*
* @return string[] this is an array of strings containing all the files that the
* current Image depends on
*/
public function getDependencies()
{
$dependencies = array();
$file = $this->getFilePath();
if ($file) {
$dependencies[] = $file;
}
foreach ($this->operations as $operation) {
foreach ($operation[1] as $argument) {
if ($argument instanceof self) {
$dependencies = array_merge($dependencies, $argument->getDependencies());
}
}
}
return $dependencies;
}
/**
* Applies the operations.
*/
public function applyOperations()
{
// Renders the effects
foreach ($this->operations as $operation) {
call_user_func_array(array($this->adapter, $operation[0]), $operation[1]);
}
}
/**
* Initialize the adapter.
*/
public function init()
{
$this->getAdapter()->init();
}
/**
* Save the file to a given output.
*/
public function save($file, $type = 'guess', $quality = 80)
{
if ($file) {
$directory = dirname($file);
if (!is_dir($directory)) {
@mkdir($directory, 0777, true);
}
}
if (is_int($type)) {
$quality = $type;
$type = 'jpeg';
}
if ($type == 'guess') {
$type = $this->guessType();
}
if (!isset(self::$types[$type])) {
throw new \InvalidArgumentException('Given type ('.$type.') is not valid');
}
$type = self::$types[$type];
try {
$this->init();
$this->applyOperations();
$success = false;
if (null == $file) {
ob_start();
}
if ($type == 'jpeg') {
$success = $this->getAdapter()->saveJpeg($file, $quality);
}
if ($type == 'gif') {
$success = $this->getAdapter()->saveGif($file);
}
if ($type == 'png') {
$success = $this->getAdapter()->savePng($file);
}
if ($type == 'webp') {
$success = $this->getAdapter()->saveWebP($file, $quality);
}
if (!$success) {
return false;
}
return null === $file ? ob_get_clean() : $file;
} catch (\Exception $e) {
if ($this->useFallbackImage) {
return null === $file ? file_get_contents($this->fallback) : $this->getCacheFallback();
} else {
throw $e;
}
}
}
/**
* Get the contents of the image.
*/
public function get($type = 'guess', $quality = 80)
{
return $this->save(null, $type, $quality);
}
/* Image API */
/**
* Image width.
*/
public function width()
{
return $this->getAdapter()->width();
}
/**
* Image height.
*/
public function height()
{
return $this->getAdapter()->height();
}
/**
* Tostring defaults to jpeg.
*/
public function __toString()
{
return $this->guess();
}
/**
* Returning basic html code for this image.
*/
public function html($title = '', $type = 'jpg', $quality = 80)
{
return '<img title="'.$title.'" src="'.$this->cacheFile($type, $quality).'" />';
}
/**
* Returns the Base64 inlinable representation.
*/
public function inline($type = 'jpg', $quality = 80)
{
$mime = $type;
if ($mime == 'jpg') {
$mime = 'jpeg';
}
return 'data:image/'.$mime.';base64,'.base64_encode(file_get_contents($this->cacheFile($type, $quality, true)));
}
/**
* Creates an instance, usefull for one-line chaining.
*/
public static function open($file = '')
{
return new static($file);
}
/**
* Creates an instance of a new resource.
*/
public static function create($width, $height)
{
return new static(null, $width, $height);
}
/**
* Creates an instance of image from its data.
*/
public static function fromData($data)
{
$image = new static();
$image->setData($data);
return $image;
}
/**
* Creates an instance of image from resource.
*/
public static function fromResource($resource)
{
$image = new static();
$image->setResource($resource);
return $image;
}
}
@@ -0,0 +1,98 @@
<?php
namespace Gregwar\Image;
/**
* Color manipulation class.
*/
class ImageColor
{
private static $colors = array(
'black' => 0x000000,
'silver' => 0xc0c0c0,
'gray' => 0x808080,
'teal' => 0x008080,
'aqua' => 0x00ffff,
'blue' => 0x0000ff,
'navy' => 0x000080,
'green' => 0x008000,
'lime' => 0x00ff00,
'white' => 0xffffff,
'fuschia' => 0xff00ff,
'purple' => 0x800080,
'olive' => 0x808000,
'yellow' => 0xffff00,
'orange' => 0xffA500,
'red' => 0xff0000,
'maroon' => 0x800000,
'transparent' => 0x7fffffff,
);
public static function gdAllocate($image, $color)
{
$colorRGBA = self::parse($color);
$b = ($colorRGBA) & 0xff;
$colorRGBA >>= 8;
$g = ($colorRGBA) & 0xff;
$colorRGBA >>= 8;
$r = ($colorRGBA) & 0xff;
$colorRGBA >>= 8;
$a = ($colorRGBA) & 0xff;
$c = imagecolorallocatealpha($image, $r, $g, $b, $a);
if ($color == 'transparent') {
imagecolortransparent($image, $c);
}
return $c;
}
public static function parse($color)
{
// Direct color representation (ex: 0xff0000)
if (!is_string($color) && is_numeric($color)) {
return $color;
}
// Color name (ex: "red")
if (isset(self::$colors[$color])) {
return self::$colors[$color];
}
if (is_string($color)) {
$color_string = str_replace(' ', '', $color);
// Color string (ex: "ff0000", "#ff0000" or "0xfff")
if (preg_match('/^(#|0x|)([0-9a-f]{3,6})/i', $color_string, $matches)) {
$col = $matches[2];
if (strlen($col) == 6) {
return hexdec($col);
}
if (strlen($col) == 3) {
$r = '';
for ($i = 0; $i < 3; ++$i) {
$r .= $col[$i].$col[$i];
}
return hexdec($r);
}
}
// Colors like "rgb(255, 0, 0)"
if (preg_match('/^rgb\(([0-9]+),([0-9]+),([0-9]+)\)/i', $color_string, $matches)) {
$r = $matches[1];
$g = $matches[2];
$b = $matches[3];
if ($r >= 0 && $r <= 0xff && $g >= 0 && $g <= 0xff && $b >= 0 && $b <= 0xff) {
return ($r << 16) | ($g << 8) | ($b);
}
}
}
throw new \InvalidArgumentException('Invalid color: '.$color);
}
}
+19
View File
@@ -0,0 +1,19 @@
Copyright (c) <2012-2017> Grégoire Passault
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.
+5
View File
@@ -0,0 +1,5 @@
cs:
php-cs-fixer fix --verbose
test:
phpunit -c phpunit.xml.dist
+278
View File
@@ -0,0 +1,278 @@
# Gregwar's Image class
[![Build status](https://travis-ci.org/Gregwar/Image.svg?branch=master)](https://travis-ci.org/Gregwar/Image)
[![paypal](https://www.paypalobjects.com/en_US/i/btn/btn_donateCC_LG.gif)](https://www.paypal.com/cgi-bin/webscr?cmd=_s-xclick&hosted_button_id=YUXRLWHQSWS6L)
The `Gregwar\Image` class purpose is to provide a simple object-oriented images handling and caching API.
# Installation
With composer :
``` json
{
...
"require": {
"gregwar/image": "2.*"
}
}
```
# Usage
## Basic handling
Using methods chaining, you can open, transform and save a file in a single line:
```php
<?php use Gregwar\Image\Image;
Image::open('in.png')
->resize(100, 100)
->negate()
->save('out.jpg');
```
Here are the resize methods:
* `resize($width, $height, $background)`: resizes the image, will preserve scale and never
enlarge it (background is `red` in order to understand what happens):
![resize()](doc/resize.jpg)
* `scaleResize($width, $height, $background)`: resizes the image, will preserve scale, can enlarge
it (background is `red` in order to understand what happens):
![scaleResize()](doc/scaleResize.jpg)
* `forceResize($width, $height, $background)`: resizes the image forcing it to
be exactly `$width` by `$height`
![forceResize()](doc/forceResize.jpg)
* `cropResize($width, $height, $background)`: resizes the image preserving scale (just like `resize()`)
and croping the whitespaces:
![cropResize()](doc/cropResize.jpg)
* `zoomCrop($width, $height, $background, $xPos, $yPos)`: resize and crop the image to fit to given dimensions:
![zoomCrop()](doc/zoomCrop.jpg)
* In `zoomCrop()`, You can change the position of the resized image using the `$xPos` (center, left or right) and `$yPos` (center,
top or bottom):
![zoomCrop() with yPos=top](doc/zoomCropTop.jpg)
The other methods available are:
* `crop($x, $y, $w, $h)`: crops the image to a box located on coordinates $x,y and
which size is $w by $h
* `negate()`: negates the image colors
* `brighness($b)`: applies a brightness effect to the image (from -255 to +255)
* `contrast($c)`: applies a contrast effect to the image (from -100 to +100)
* `grayscale()`: converts the image to grayscale
* `emboss()`: emboss the image
* `smooth($p)`: smooth the image
* `sharp()`: applies a mean removal filter on the image
* `edge()`: applies an edge effect on the image
* `colorize($red, $green, $blue)`: colorize the image (from -255 to +255 for each color)
* `sepia()`: applies a sepia effect
* `merge($image, $x, $y, $width, $height)`: merges two images
* `fill($color, $x, $y)`: fills the image with the given color
* `write($font, $text, $x, $y, $size, $angle, $color, $position)`: writes text over image, $position can be any of 'left', 'right', or 'center'
* `rectangle($x1, $y1, $x2, $y2, $color, $filled=false)`: draws a rectangle
* `rotate($angle, $background = 0xffffff)` : rotate the image to given angle
* `roundedRectangle($x1, $y1, $x2, $y2, $radius, $color, $filled=false)`: draws a rounded rectangle ($radius can be anything from 0)
* `line($x1, $y1, $x2, $y2, $color)`: draws a line
* `ellipse($cx, $cy, $width, $height, $color, $filled=false)`: draws an ellipse
* `circle($cx, $cy, $r, $color, $filled=false)`: draws a circle
* `fillBackground($bg=0xffffff)`: fills the background of a transparent image to the 'bg' color
* `fixOrientation()`: return the image rotated and flipped using image exif information
* `applyExifOrientation(int $exif_rotation_value)`: return the image rotated and flipped using an exif rotation value
* `html($title = '', $type = 'jpg')`: return the `<img ... />` tag with the cache image
* `flip($flipVertical, $flipHorizontal)`: flips the image in the given directions. Both params are boolean and at least one must be true.
* `inline($type = 'jpg')`: returns the HTML inlinable base64 string (see `demo/inline.php`)
You can also create image from scratch using:
```php
<?php
Image::create(200, 100);
```
Where 200 is the width and 100 the height
## Saving the image
You can save the image to an explicit file using `save($file, $type = 'jpg', $quality = 80)`:
```php
<?php
// ...
$image->save('output.jpg', 'jpg', 85);
```
You can also get the contents of the image using `get($type = 'jpg', $quality = 80)`, which will return the binary contents of the image
## Using cache
Each operation above is not actually applied on the opened image, but added in an operations
array. This operation array, the name, type and modification time of file are hashed using
`sha1()` and the hash is used to look up for a cache file.
Once the cache directory configured, you can call the following methods:
* `jpeg($quality = 80)`: lookup or create a jpeg cache file on-the-fly
* `gif()`: lookup or create a gif cache file on-the-fly
* `png()`: lookup or create a png cache file on-the-fly
* `guess($quality = 80)`: guesses the type (use the same as input) and lookup or create a
cache file on-the-fly
* `setPrettyName($prettyName, $prefix = true)`: sets a "pretty" name suffix for the file, if you want it to be more SEO-friendly.
for instance, if you call it "Fancy Image", the cache will look like something/something-fancy-image.jpg.
If `$prefix` is passed to `false` (default `true`), the pretty name won't have any hash prefix.
If you want to use non-latin1 pretty names, **behat/transliterator** package must be installed.
For instance:
```php
<?php use Gregwar\Image\Image;
echo Image::open('test.png')
->sepia()
->jpeg();
//Outputs: cache/images/1/8/6/9/c/86e4532dbd9c073075ef08e9751fc9bc0f4.jpg
```
If the original file and operations do not change, the hashed value will be the same and the
cache will not be generated again.
You can use this directly in an HTML document:
```php
<?php use Gregwar\Image\Image;
// ...
<img src="<?php echo Image::open('image.jpg')->resize(150, 150)->jpeg(); ?>" />
// ...
```
This is powerful since if you change the original image or any of your code the cached hash
will change and the file will be regenerated.
Writing image
-------------
You can also create your own image on-the-fly using drawing functions:
```php
<?php
$img_src = Image::create(300, 300)
->fill(0xffaaaa) // Filling with a light red
->rectangle(0xff3333, 0, 100, 300, 200, true) // Drawing a red rectangle
// Writing "Hello $username !" on the picture using a custom TTF font file
->write('./fonts/CaviarDreams.ttf', 'Hello '.$username.'!', 150, 150, 20, 0, 'white', 'center')
->jpeg();
?>
<img src="<?= $img_src ?>" />
```
## Using fallback image
If the image file doesn't exists, you can configurate a fallback image that will be used
by the class (note that this require the cache directory to be available).
A default "error" image which is used is in `images/error.jpg`, you can change it with:
```php
<?php
$img->setFallback('/path/to/my/fallback.jpg');
```
## Garbage Collect
To prevent the cache from growing forever, you can use the provided GarbageCollect class as below:
```php
<?php use Gregwar\Image\GarbageCollect;
// This could be a cron called each day @3:00AM for instance
// Removes all the files from ../cache that are more than 30 days
// old. A verbose output will explain which files are deleted
GarbageCollect::dropOldFiles(__DIR__.'/../cache', 30, true);
```
# Development
`Gregwar\Image` is using PHP metaprogramming paradigms that makes it easy to enhance.
Each function that handles the image is implemented in an *Adapter*, this is where
all the specific actions take place.
The `Common` adapter is design to contain common abstract actions, while the
specific adapters (like `GD`) are designed to contain actions specific to the low
level layer.
You can add your own methods by adding it in the corresponding adapter.
```php
<?php
// In the adapter
private function myFilter()
{
$this->negate();
$this->sepia();
}
```
Which could be used on the Image
```php
<?php
$image->myFilter();
```
You can also write your own adapter which could extend one of this repository and use it by calling `setAdapter()`:
```php
<?php
$image->setAdapter(new MyCustomAdapter);
```
# License
`Gregwar\Image` is under MIT License, please read the LICENSE file for further details.
Do not hesitate to fork this repository and customize it !
@@ -0,0 +1,38 @@
<?php
namespace Gregwar\Image\Source;
/**
* Creates a new image from scratch.
*/
class Create extends Source
{
protected $width;
protected $height;
public function __construct($width, $height)
{
$this->width = $width;
$this->height = $height;
}
public function getWidth()
{
return $this->width;
}
public function getHeight()
{
return $this->height;
}
public function getInfos()
{
return array($this->width, $this->height);
}
public function correct()
{
return $this->width > 0 && $this->height > 0;
}
}
@@ -0,0 +1,26 @@
<?php
namespace Gregwar\Image\Source;
/**
* Having image in some string.
*/
class Data extends Source
{
protected $data;
public function __construct($data)
{
$this->data = $data;
}
public function getData()
{
return $this->data;
}
public function getInfos()
{
return sha1($this->data);
}
}
@@ -0,0 +1,67 @@
<?php
namespace Gregwar\Image\Source;
use Gregwar\Image\Image;
/**
* Open an image from a file.
*/
class File extends Source
{
protected $file;
public function __construct($file)
{
$this->file = $file;
}
public function getFile()
{
return $this->file;
}
public function correct()
{
return false !== @exif_imagetype($this->file);
}
public function guessType()
{
if (function_exists('exif_imagetype')) {
$type = @exif_imagetype($this->file);
if (false !== $type) {
if ($type == IMAGETYPE_JPEG) {
return 'jpeg';
}
if ($type == IMAGETYPE_GIF) {
return 'gif';
}
if ($type == IMAGETYPE_PNG) {
return 'png';
}
if ($type == IMAGETYPE_WEBP) {
return 'webp';
}
}
}
$parts = explode('.', $this->file);
$ext = strtolower($parts[count($parts) - 1]);
if (isset(Image::$types[$ext])) {
return Image::$types[$ext];
}
return 'jpeg';
}
public function getInfos()
{
return $this->file;
}
}
@@ -0,0 +1,21 @@
<?php
namespace Gregwar\Image\Source;
/**
* Have the image directly in a specific resource.
*/
class Resource extends Source
{
protected $resource;
public function __construct($resource)
{
$this->resource = $resource;
}
public function getResource()
{
return $this->resource;
}
}
@@ -0,0 +1,34 @@
<?php
namespace Gregwar\Image\Source;
/**
* An Image source.
*/
class Source
{
/**
* Guess the type of the image.
*/
public function guessType()
{
return 'jpeg';
}
/**
* Is this image correct ?
*/
public function correct()
{
return true;
}
/**
* Returns information about images, these informations should
* change only if the original image changed.
*/
public function getInfos()
{
return;
}
}
+21
View File
@@ -0,0 +1,21 @@
<?php
$vendors = __DIR__.'/vendor/autoload.php';
if (file_exists($vendors)) {
return require $vendors;
}
/*
* Registers an autoload for all the classes in Gregwar\Image
*/
spl_autoload_register(function ($className) {
$namespace = 'Gregwar\\Image';
if (strpos($className, $namespace) === 0) {
$className = str_replace($namespace, '', $className);
$fileName = __DIR__.'/'.str_replace('\\', '/', $className).'.php';
if (file_exists($fileName)) {
require $fileName;
}
}
});

Some files were not shown because too many files have changed in this diff Show More