作者归档:admin

上传、下载

上传

配置支持的后缀

# 上传相关
UPLOAD_SIZE = 100
UPLOAD_EXT = jpg,jpeg,png,gif,bmp,doc,docs,xls,xlsx,pdf,ppt,video,mp4,mp3,webm

element ui 上传

<el-upload style="margin-left:10px;"
  accept="<?=lib\Mime::get('video,mp4,mp3,webm')?>"
  class="none"
  action="/admin/media/upload" 
  :on-success="(response, file, fileList) => {
    return video_success(response, file, fileList, scope.row);
  }"  >
  <el-button size="small" type="primary">上传</el-button> 
</el-upload>

下载

远程下载限制mime

add_action("allow_mime",function(&$mime){
    $mime[] = "webm";
    $mime[] = "video";
    $mime[] = "mp4";
    $mime[] = "mp3";
});

默认可下载的文件

['jpg','jpeg','png','gif','pdf','xls','xlsx','doc','docx','ppt','pptx']

调用

download_file_safe($url, $mimes = ['image/*','video/*'], $cons = [], $contain_http = false)

uniapp

<cl-upload :headers="upload_header" v-model="form.file" :action="upload_url"></cl-upload>

upload_url:'',
upload_header:{}

this.upload_url = this.config.upload_url
this.upload_header = this.get_header() 

小程序 隐私保护指引

配置 -> 用户使用协议

添加标题为 隐私保护指引 的内容。

模板

xx小程序隐私保护说明
本指引是xx小程序开发者(以下简称“开发者”)为处理你的个人信息而制定。

开发者处理的信息
根据法律规定,开发者仅处理实现小程序功能所必要的信息。

为了注册、登录小程序,开发者收集你的用户信息(微信昵称、头像、性别、地区)。
开发者收集你的手机号码,用于网约车司机与你取得联系。
开发者收集你的身份证号码,用于法律实名制要求,为你提供车票购买服务。
第三方插件信息/SDK信息
为实现特定功能,开发者可能会接入由第三方提供的插件/SDK。第三方插件/SDK的个人信息处理规则,请以其公示的官方说明为准。XXX小程序接入的第三方插件信息/SDK信息如下:

第三方插件信息
插件名称:xxx

插件提供方名称: xxxxxx

为了注册、登录小程序,开发者收集你的用户信息(微信昵称、头像、性别、地区)。
开发者收集你的手机号码,用于网约车司机与你取得联系。
开发者收集你的身份证号码,用于法律实名制要求,为你提供车票购买服务。
第三方SDK信息
SDK名称: xxxx

SDK提供方名称: xxxxxx

为了注册、登录小程序,开发者收集你的用户信息(微信昵称、头像、性别、地区)。
开发者收集你的手机号码,用于网约车司机与你取得联系。
开发者收集你的身份证号码,用于法律实名制要求,为你提供车票购买服务。
你的权益
开发者承诺,除法律法规另有规定外,开发者对你的信息的保存期限应当为实现处理目的所必要的最短时间。

关于xxxx,你可以通过以下路径:小程序主页右上角“…”—“设置”—点击特定信息—点击“不允许”,撤回对开发者的授权。

关于你的个人信息,你可以通过以下方式与开发者联系,行使查阅、复制、更正、删除等法定权利。

邮箱: xxxx@tenent.com

开发者对信息的存储
开发者承诺,除法律法规另有规定外,开发者对你的信息的保存期限应当为实现处理目的所必要的最短时间。

开发者将你的信息存储在 中国大陆。(仅境外主体小程序需要填写)

信息的使用规则
开发者将会在本指引所明示的用途内使用收集的信息

如开发者使用你的信息超出本指引目的或合理范围,开发者必须在变更使用目的或范围前,再次以xxx方式告知并征得你的明示同意。

信息对外提供
开发者承诺,不会主动共享或转让你的信息至任何第三方,如存在确需共享或转让时,开发者应当直接征得或确认第三方征得你的单独同意。

开发者承诺,不会对外公开披露你的信息,如必须公开披露时,开发者应当向你告知公开披露的目的、披露信息的类型及可能涉及的信息,并征得你的单独同意。

你认为开发者未遵守上述约定,或有其他的投诉建议、或未成年人个人信息保护相关问题,可通过以下方式与开发者联系;或者向微信进行投诉。

邮箱: xxxx@tenent.com

更新日期:2024-04-15

生效日期:2024-04-15

banner

模块中 app.php

/**
* 取banner
*/
function get_h_banner(){
    for($i=1;$i<=5;$i++){
        $cc[] = "banner_img_".$i;
        $cc[] = "banner_url_".$i;
        $cc[] = "banner_status_".$i;
    }
    $all = get_config($cc);
    $list = [];
    for($i=1;$i<=5;$i++){
        $img = "banner_img_".$i;
        $url = "banner_url_".$i;
        $status = "banner_status_".$i; 
        if($all[$img] && $all[$status] == 1){
            $list[cdn_url().$all[$img]] = $all[$url];
        }
    } 
    return $list;
}

add_action('admin.config.config_key',function(&$config_key){
    $config_key[] = 'enroll_open_note';  
    $config_key[] = 'enroll_close_note'; 

    for($i=1;$i<=5;$i++){
        $config_key[] = "banner_img_".$i;
        $config_key[] = "banner_url_".$i;
        $config_key[] = "banner_status_".$i;
    }       
}); 
add_action('admin.config.tab',function(){
    if(is_admin()){
        echo '<li><a href="#hbanner" name="" >轮播图</a></li>';
    }
});
add_action('admin.config.body',function(&$vue){
    if(is_admin()){ 
        include __DIR__.'/config.php';    
    }    
});

同级config.php

<div id="hbanner"  class=" input_100" >    
	<label>首页轮播图</label>
	<table class="pure-table pure-table-bordered" style="width:80%">
	    <thead>
	        <tr>
	            <th>图片</th>
	            <th>地址</th>
	            <th>操作</th> 
	        </tr>
	    </thead>
	    <tbody>
	    	<?php for($i=1;$i<=5;$i++){?>
		        <tr >
		            <td>
		            	<?php think_vue_media_one_button('banner_img_'.$i,'form',$show_del = true)?>   
		            </td>
		            <td>
		            	<input v-model="form.banner_url_<?=$i?>" style="width:80%;">
		            </td>
		            <td>
		            	<el-checkbox v-model="form.banner_status_<?=$i?>" true-label="1" false-label="-1"></el-checkbox>
		            </td> 
		        </tr> 
		    <?php }?>
	    </tbody>
	</table> 
	<?php   
	think_vue_media($vue,"   
	    for(let i in dd){
	        if(dd[i] && dd[i].url){
	            this.\$set(this.form,this.media_name, dd[i].url);    
	        } 
	    }"," 
	    this.selected_media_use_muit = false; 
	");
	$vue->method("remove_media_one(name)","  
	    this.\$set(this.form , name, '');    
	    this.\$forceUpdate();
	"); 
	?>

	<!-- <el-row>  
	  <el-col :span="12" style="padding-right: 10px;">  
 		<div class="mt10 "  >
 			<div>
 				<label>查看活动时弹出提示</label>
 				<el-input placeholder="每次查看活动都会弹出" type="textarea"  cols="3" v-model="form.enroll_open_note"></el-input>
 			</div> 
 		</div>
 		<div class="mt10 "  >
 			<div>
 				<label>禁用活动时弹出提示</label>
 				<el-input placeholder="活动下线时,默认是不显示在活动列表中的,但当填写此处内容时就会在列表中显示,用户点击时弹出提示" type="textarea" cols="3"  v-model="form.enroll_close_note"></el-input>
 			</div> 
 		</div> 

	    
	  </el-col>


	</el-row> -->
	<div class="mt10"> 
	    <button class="button-xsmall pure-button pure-button-primary" @click="save()">保 存</button>   
	</div>
</div>

<?php  
?>

Banner图上传

多图

<?php think_vue_media_button('home_banner','form',$click_image='')?>  
think_vue_media($vue," 
        console.log(this.media_name);
		if(!this.form.home_banner){
			this.form.home_banner = [];
		}
	    for(let i in dd){
	        if(dd[i] && dd[i].url){
	            this.form.home_banner.push(dd[i].url);    
	        } 
	    }"," 
	    this.selected_media_use_muit = false; 
	");
	$vue->method("remove_home_banner(index)","
	    this.form.home_banner.splice(index,1); 
	");

单图

<?php think_vue_media_one_button('image')?>  
think_vue_media($vue,"  
        console.log(this.media_name);
		this.form.image = ''; 
	    for(let i in dd){
	        if(dd[i] && dd[i].url){
	            this.form.image = dd[i].url;    
	        } 
	    }"," 
	    this.selected_media_use_muit = false; 
	");
	$vue->method("remove_image()"," 
	    this.form.image = ''; 
	    this.\$forceUpdate();
	");

表格图片

<table class="pure-table pure-table-bordered" style="width:80%">
    <thead>
        <tr>
            <th>图片</th>
            <th>地址</th>
            <th>操作</th> 
        </tr>
    </thead>
    <tbody>
    	<?php for($i=1;$i<5;$i++){?>
	        <tr >
	            <td>
	            	<?php think_vue_media_one_button('banner_url_'.$i,'form',$show_del = true)?>   
	            </td>
	            <td>
	            	
	            </td>
	            <td>

	            </td> 
	        </tr> 
	    <?php }?>
    </tbody>
</table>
think_vue_media($vue,"   
    for(let i in dd){
        if(dd[i] && dd[i].url){
            this.\$set(this.form,this.media_name, dd[i].url);    
        } 
    }"," 
    this.selected_media_use_muit = false; 
");
$vue->method("remove_media_one(name)","  
    this.\$set(this.form , name, '');    
    this.\$forceUpdate();
"); 

任务处理

  • 包名 cli_tasks

至少存在一台主服务,用于分发任务到每台具体处理任务的机器上。

注册主服务器

php cli.php reg_main

注册处理任务的服务器

php cli.php reg_branch

使用

  • 主机分发任务
php cli.php issue
  • 处理任务
php cli.php task
  • 添加任务
php cli.php task_add --title=演示  --cmd=task_demo

其中task_demo 需要在命令行中存在,如果有参数请加 --par=

php cli.php task_add --title=test --cmd=demo --par=InNzc3Mi

par参数是由

$str = 'demo';//可以是数组或字符串
base64_encode(json_encode($str));

测试

php cli.php demo --par=InNzc3Mi
  • 心跳
php cli.php heartbeat

php.ini

删除禁用函数 shell_exec

写任务

任务目录 task

命名规则 task_开头,但不能为task_add.php

例如 task_dowonload.php

<?php  
namespace task; 
use third_party\mac;
class task_dowonload extends \cli
{ 
    protected string $description = "本地测试 --url=参数 "; 
    //最多同时运行进程数
    public $max_run = 2;
    
    protected array $options = [
        'url' => '', 
    ];

    public function run() : void
    {  
        parent::run();  
        $url = $this->arg['url];
        $this->write("---",'bright_red');
        $this->write("par值>>> ".$par,'green'); 
        $this->write("a",'blue'); 
        $this->write("a",'red'); 
        sleep(10); 
        
    }
}

则有命令 php cli.php task_dowonload --url=

run()

$this->arg[]  // 数组取参数
$this->par //为 --par=的值【base64_encode(json_encode($str)) 】

理解任务处理流程

当有多个任务时通过一台机器不能很好的处理时,此时需要多台机器处理。

1.注册服务,注册一台主机其余的均为任务处理机器。注册主机【reg_main】,注册任务机【reg_branch】。 当需要切换主机时,先将主机注册成任务机,然后再用一台机器注册为主机即可。

2.由主机进行任务的分发工作【issue】。

3.任务机器需要做两件事情,一是心跳【heartbeat】,告知主机我在线;二是处理任务【task】。

4 添加任务【task_add –title=演示 –cmd=task_demo】。

建议使用进程守护。

nodejs nvm

windows nodejs版本管理

https://github.com/coreybutler/nvm-windows/releases

使用

nvm install  14 

unoconv

安装

yum -y install unoconv
yum install -y ImageMagick ImageMagick-devel

PPT转 PDF

unoconv -f pdf  1.ppt 

指定路径

unoconv -o demo.pptx  -f pptx  1.ppt

pdf转图片

convert 1.pdf   %d.jpg

图片上传 资源管理器

支持打开图片资源管理器,选择图片插入指定元素

HTML

<el-form-item label="封面" required>
	<?php think_vue_media_button('image')?>
</el-form-item> 

VUE

<?php 
think_vue_media($vue,"  
    if(!this.form.image){
        this.form.image= [];
    }
    for(let i in dd){
        if(dd[i] && dd[i].url){
            this.form.image.push(dd[i].url);          
        } 
    } 
"," 
   this.selected_media_use_muit = true; 
");
$vue->method("remove_images(index)","
    this.form.image.splice(index,1);
    this.\$forceUpdate();
");
?>

注意其中 image 变量

LICENSE

Permission is hereby granted to any person obtaining a copy of this software
(the “Software”) to use, copy, modify, merge, publish and/or distribute copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:

  1. Don’t plagiarize. The above copyright notice and this license shall be
    included in all copies or substantial portions of the Software.
  2. Don’t use the same license on more than one project. Each licensed copy
    of the Software shall be actively installed in no more than one production
    environment at a time.
  3. Don’t mess with the licensing features. Software features related to
    licensing shall not be altered or circumvented in any way, including (but
    not limited to) license validation, payment prompts, feature restrictions,
    and update eligibility.
  4. Pay up. Payment shall be made immediately upon receipt of any notice,
    prompt, reminder, or other message indicating that a payment is owed.
  5. Follow the law. All use of the Software shall not violate any applicable
    law or regulation, nor infringe the rights of any other person or entity.

Failure to comply with the foregoing conditions will automatically and
immediately result in termination of the permission granted hereby. This
license does not include any right to receive updates to the Software or
technical support. Licensees bear all risk related to the quality and
performance of the Software and any modifications made or obtained to it,
including liability for actual and consequential harm, such as loss or
corruption of data, and any necessary service, repair, or correction.

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, INCLUDING SPECIAL, INCIDENTAL AND CONSEQUENTIAL DAMAGES, 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.

helper

https://github.com/thefunpower/helper

安装

在composer.json中添加

"thefunpower/helper": "dev-main" 

助手工具类或函数

需要定义PATH目录,项目的根目录

define("PATH",__DIR__.'/');

需要定义WWW_PATH目录,网站访问的目录,有时PATH与WWW_PATH是一样的

define("WWW_PATH",__DIR__.'/');

确保有data uploads两个目录且可写.

data在根目录 uploads在网站访问的目录

Predis Publish Subscribe

连接

predis($host,$port,$auth);

发布消息

redis_pub("demo","welcome man");
redis_pub("demo",['title'=>'yourname']);

取订阅消息

redis_sub("demo",function($channel,$message){
  echo "channel ".$channel."\n";
  print_r($message);
}); 

Predis GEO

连接

predis($host,$port,$auth);

获取

$s = predis_geo_pos('places',[
    '上海外滩','北京天安门' 
]); 
pr($s) ; 

添加

predis_add_geo('places',[
    [ 
        'lat'=>'116.397128',
        'lng'=>'39.916527',
        'title'=>'北京天安门'
    ],
    [ 
        'lat'=>'121.473701',
        'lng'=>'31.230416',
        'title'=>'上海外滩'
    ],
    [ 
        'lat'=>'121.45668',
        'lng'=>'31.21706',
        'title'=>'襄阳公园'
    ], 
]);

附近分页

pr(predis_get_pager('places', 121.45668, 31.21706));

RPC

服务端

class ServerGetUser{
    public function getInfo($name = 'abc'){
        return ['welcome'=>$name,'token'=>rpc_token()];
    }
}
rpc_server("ServerGetUser");

客户端

$client = rpc_client("http://127.0.0.1:5000/rpc.php");
$info = $client->getInfo("test");
print_r($info);

Ftp

php.ini中开启ftp扩展

把本地文件同步到FTP上。

如果FTP上目录文件已存在,将会被替换。

use helper_v3\Ftp;
$ftp = Ftp::start([
    'host' =>'IP地址',
    'user' =>'帐号',
    'pwd'  =>'密码',
    'port' =>'端口,默认21', 
]);  
//上传到根目录
Ftp::put_all(__DIR__.'/uploads');
//或上传到指定目录
//Ftp::put_all(__DIR__.'/uploads','uploads');
Ftp::end();

更多方法 https://github.com/Nicolab/php-ftp-client

PDF字体

免费字体

阿里妈妈方圆体   alifanyuan
阿里妈妈数黑体   alishuhei
阿里巴巴普惠体   puhuiti
阿里巴巴普惠体细 puhuitithin
google字体      notosanssc 

默认使用 notosanssc。

helper_v3\Pdf::init([
    'fontDir'=>[''],
    'fontdata'=>[
        'simhei'=> [
            'R' => 'simhei.ttf',
            'I' => 'simhei.ttf', 
        ],
    ],
    'default_font'=>'simhei'
]);

PDF

安装依赖

yum install pdftk   pdftk-java  poppler-utils perl-Image-ExifTool.noarch  ImageMagick ImageMagick-devel  ghostscript -y

生成PDF

https://mpdf.github.io/installation-setup/installation-v7-x.html
use helper_v3\Pdf;

$mpdf = Pdf::init();
$mpdf->WriteHTML('<h1>Hello world!</h1>');
$mpdf->Output();

合并PDF

$input = [
    PATH.'uploads/1.pdf',
    PATH.'uploads/2.pdf',
];
$new_file = '/完整路径/1.pdf';
echo Pdf::merger($input,$new_name);
exit;

合并PDF,包含图片

Pdf::merger_with_image($files, $output);

PDF提取图片

Pdf::pdf_to_image($file,$saveToDir)

取PDF信息

Pdf::get_info($file);

返回

Array
    (
        [header] => Array
            (
                [ModDate] => D
                [Creator] => Microsoft® PowerPoint® 2019
                [CreationDate] => D
                [Producer] => Microsoft® PowerPoint® 2019
                [Author] => Microsoft Office User
                [Title] => PowerPoint 演示文稿
            )
        文档长宽
        [dimensions] => Array
            (
                [0] => 960
                [1] => 540
            )
        2是横版,1是竖版
        [dimensions_type] => 2
    ) 

取PDF页数

Pdf::get_pages($file);

设置PDF信息

Pdf::set_info($file,$output,$arr = []);

其中arr支持title author keywords

生成PDF table

$html = '
<style> 
table{
    width: 100%;
    text-align:left;
    margin: 0 auto;
    border: 1px solid #000000;
    border-collapse: collapse;
} 
th,td {
    border: 1px solid #000000;
    text-align: center;
}
</style>
<table   cellspacing="0" cellpadding="0" border="0"   >
  <thead>
    <tr>
      <th scope="col">#</th>
      <th scope="col">First</th>
      <th scope="col">Last</th>
      <th scope="col">Handle</th>
    </tr>
  </thead>
  <tbody>
    <tr>
      <th scope="row">1</th>
      <td>Mark</td>
      <td>Otto</td>
      <td>@mdo</td>
    </tr>
    <tr>
      <th scope="row">2</th>
      <td>Jacob</td>
      <td>Thornton</td>
      <td>@fat</td>
    </tr>
    <tr>
      <th scope="row">3</th>
      <td colspan="2">Larry the Bird</td>
      <td>@twitter</td>
    </tr>
  </tbody>
</table>';
    $mpdf = Pdf::init();
    $mpdf->shrink_tables_to_fit = 1;
    $mpdf->WriteHTML($html);
    $mpdf->Output();

HTML转PDF

安装依赖

yum install xorg-x11-server-Xvfb wkhtmltopdf  fontconfig freetype wqy-zenhei-fonts wqy-microhei-fonts 

PHP中调用

html_to_pdf($input_html_file,$output_pdf_file,$return_cmd = false,$exec = false)

如遇条形码可用 php-barcode-generator

composer require picqer/php-barcode-generator

Xls

composer require phpoffice/phpspreadsheet

当前使用 "phpoffice/phpspreadsheet": "^1.20"

生成xls

use helper_v3\Xls;

$all = db_get("catalog_product",'*');

foreach($all as $v){
    $title = $v['title'];
    $desc = $v['desc'];
    $values[] = [
        'title'=>$title,
        'desc'=>$desc,
    ];
}
Xls::create([
    'title'=>'编号',
    'desc'=>'规格',
], $values, 'product', FALSE);

第一个worksheet

Xls::$label = $txt_month.'专票';
Xls::$sheet_width = [
    'A' => "15",
    'B' => "36",
    'C' => "30",
    'D' => "10",
    'E' => "10",
    'F' => "10",
];

更多worksheet

Xls::$works = [
    [
        'title' => $title,
        'label' => $txt_month.'普票',
        'data'  => $new_data,
        'width' => Xls::$sheet_width,
    ]
];

合并

Xls::$merge = [
    'A18:E22' 
];
Xls::create($title, $values, $name, FALSE);

消息订阅

依赖

yarn add ioredis 
yarn add ws 

1.生成server.js

echo create_node_ws_server($ws_port=3006,$topic=['demo'],$redis_host='127.0.0.1',$port='6379',$auth='');

复制代码至server.js

启动server

node server.js

2.HTML添加监听

依赖 reconnecting-websocket.js

https://github.com/joewalnes/reconnecting-websocket
<script>
<?php 
$func = " 
    data = JSON.parse(data);
    console.log(data);
";
echo get_ws_js($func,'ws://127.0.0.1:3006');
?>
</script>

其中ws://127.0.0.1:3006 如果是 wss 则wss://yourdomain/wss

3.php发送消息

redis_pub("demo",['title'=>'yourname']);

如使用wss则需配置Nginx转发

location /wss {
    proxy_pass http://127.0.0.1:3006;
    proxy_set_header X-Real-IP $remote_addr;
    proxy_set_header Host $host;
    proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
    proxy_http_version 1.1;
    proxy_set_header Upgrade $http_upgrade;
    proxy_set_header Connection "upgrade";
    rewrite /wss/(.*) /$1 break;
    proxy_redirect off;
}

测试

redis_sub("demo",function($channel,$message){
  echo "channel ".$channel."\n";
  print_r($message);
});

pusher

https://pusher.com/
PUSHER_APP_KEY = 
PUSHER_APP_SECRET = 
PUSHER_APP_ID = 
PUSHER_APP_CLUSTER =  

前端需要加载JS

<script src="https://js.pusher.com/8.0.1/pusher.min.js"></script>
<script type="text/javascript">
var pusher = new Pusher("<?=get_config("PUSHER_APP_KEY")?>", {
  cluster: "<?=get_config("PUSHER_APP_CLUSTER")?>",
});
var channel = pusher.subscribe("netteadmin");
channel.bind("notice", (data) => {
   console.log(data);
});
</script>

发送消息

helper_v3\Pusher::sender($channel,$event,$data = []);
或使用
send_pusher($data = [],$channel='netteadmin',$event='notice');

xcookie 加密

//设置
xcookie("ss",1);
xcookie("ss",['title'=>'tt']);
//读取
pr(xcookie("ss"));
//删除
xcookie_delete("ss");  

redis锁

global $redis_lock; 
//锁前缀
global $lock_key;

$redis_lock = [
    'host'=>'',
    'port'=>'',
    'auth'=>'',
];

lock_call('k',functon(){

},second); 

gz压缩数据

$s = gz_encode(['a'=>"test"]);
echo $s; 
echo "解压后<br>";
print_r(gz_decode($s));

SCSS

scss链接

<link rel="stylesheet" href="<?=scss("app.scss",true)?>" />

也可以直接调用

<style>
<?php 
echo scss("
 \$color: #abc;
 div { color: lighten(\$color, 20%); }
");
<?php }?>
</style>

scss文件语法,参考 http://www.uinio.com/Web/Scss/

$color: red;
.navigation {
    ul {
        line-height: 20px;
        color: blue;
        a {
            color: $color;
        }

    }
}

.footer {
    .copyright {
        color: silver;
    }
}