分类目录归档:Uncategorized

Nginx 限流

在nginx主配置中加

http {
     limit_req_zone $binary_remote_addr zone=nglimit:100m rate=200r/s; 
}

100m 用于指定限流区域 nglimit 所占用的内存空间。这个值通常需要根据服务器的性能和预期的请求频率来合理设置。内存的分配越大,存储的状态信息越多,可以更准确地进行请求限流,但也会占用更多的服务器内存。

200r/s 每秒允许的请求频率

站点中修改

location / {
  limit_req zone=nglimit burst=100 nodelay; 
}
  • burst=100 允许的突发请求数等。

以宝塔为例

NG

站点

burst 参数用于设置允许的突发请求数。这个参数指定了在限流策略生效时,允许在一次请求周期内突发处理的最大请求数量。当达到限流的请求频率时,如果有突发请求超过了指定的 burst 数量,Nginx 会暂时允许处理这些突发请求,而不会立即进行限流处理。

换句话说,burst 参数用于控制限流策略在短期内对突发请求的处理方式。例如,如果您设置了 rate=200r/s(每秒允许请求频率为 200 次)和 burst=100,那么在一秒钟内允许的请求数为 200 个,但如果有突发请求,最多可以允许处理 300 个请求,以平滑处理请求峰值。

内容类型

这是一个实验性软件,为了减少书写表格、表单、接口、权限而开发。

能够有效的处理一些业务场景。可以少写代码甚至不写代码即可完成后端开发。

  • 内容类型
  • 内容管理
  • 内容权限
  • 内容接口

当有 author字段及status字段时,后台仅能审核。

status对应值 ok err wait

接口调用只是自己的需传 use_author = 1

内容类型:用于创建不同的内容类型,管理字段,配置列表、表单、搜索

内容管理:用于管理由内容类型创建的内容。支持列表显示、添加、编辑、删除、搜索操作。

部分截图

接口

/cck/api_content/pager?_type=blog
/cck/api_content/tree?_type=blog
/cck/api_content/show?_type=blog&id=6625d47712650dfe9f0314a3

表单2.0

https://github.com/thefunpower/element

安装

在composer.json中添加

composer require thefunpower/element

使用

搜索

<?php 
echo element("filter",[ 
    'data'=>'list',
    'url'=>'/video/group/get_pager',
    'is_page'=>true,
    'init'=>true,
    [
        'type'=>'input','name'=>'title',
        'attr_element'=>[
            'placeholder'=>'名称',
        ],
    ],
]); 
?>

表格

<?php 
echo element('table',[
    ['name'=>'open',':data'=>'list',':height'=>'height'],
    ['name'=>'column','prop'=>'title','label'=>'名称','width'=>''],
    ['name'=>'column','prop'=>'count','label'=>'成员数','width'=>''],
    ['name'=>'column','prop'=>'count','label'=>'操作','width'=>'100',
      'tpl'=>[
          ['name'=>'button','label'=>'成员','@click'=>'show_user(scope.row)'],
          ['name'=>'button','label'=>'编辑','@click'=>'edit(scope.row)','style'=>'margin-left: 20px;'],
       ]
    ],
    ['name'=>'close'],
]);
?> 

分页

<?php 
echo element("pager",[ 
    'data'=>'list',
    'url'=>'/video/group/get_pager', 
    'reload_data'=>[]
]); 
?> 

表单

echo element('form',[ 
    ['type'=>'open','model'=>'form','label-width'=>'180px'],
    [
        'type'=>'input','name'=>'title','label'=>'标题',
        'attr'=>['title'=>'演示标题'],
    ],
    [
        'type'=>'color','name'=>'aa31','label'=>'color', 
    ],
    [
        'type'=>'datetime','name'=>'aa32','label'=>'datetime', 
    ],
    [
        'type'=>'time','name'=>'aa33','label'=>'time', 
    ],
    [
        'type'=>'tag','name'=>'tag','label'=>'tag', 
    ],
    [
        'type'=>'sku','name'=>'sku','label'=>'sku',         
        'js'=>"app.add_media('upload_spec');"
    ],
    [
        'type'=>'checkbox','name'=>'checkbox','label'=>'多选',
        'value'=>[['label'=>'选项1','value'=>1],['label'=>'选项2','value'=>2],], 
    ],
    [
        'type'=>'radio','name'=>'radio','label'=>'radio',
        'value'=>[['label'=>'选项1','value'=>1],['label'=>'选项2','value'=>2],], 
    ],
    
    [
        'type'=>'text','name'=>'text','label'=>'text', 
        'attr'=>['required',],
        'attr_element'=>[':rows'=>10],
    ],

    [
        'type'=>'editor','name'=>'editor','label'=>'editor',  
    ],

    [
        'type'=>'attribute','name'=>'attribute','label'=>'attribute', 
        'value'=>[ ['label'=>'选项1','value'=>1],['label'=>'选项2','value'=>2],],  
    ],

    [
        'type'=>'select','name'=>'select1','label'=>'select单选', 
        'value'=>[ ['label'=>'选项1','value'=>1],['label'=>'选项2','value'=>2],],  
    ],
    [
        'type'=>'select','name'=>'select2','label'=>'select多选', 
        'value'=>[ ['label'=>'选项1','value'=>1],['label'=>'选项2','value'=>2],], 
        'attr_element'=>['multiple'],
    ],
    [
        'type'=>'date','name'=>'date1','label'=>'时间', 
        'attr'=>['title'=>''], 
        'attr_element'=>[':picker-options'=>'pickerOptions','align'=>"center"],
    ],
    [
        'type'=>'autocomplete','name'=>'aa','label'=>'autocomplete', 
        'url'=>'/video/group/autocomplete',  
    ],

    [
        'type'=>'cascader','name'=>'bb','label'=>'cascader', 
        //':props'="{ checkStrictly: true }",
        'url'=>'/video/group/cascader', 
        'attr_element'=>[':props'=>"{value:'id',label:'label'}"],
    ],

    [
        'type'=>'upload','name'=>'fiel','label'=>'上传', 
        'url'=>'/upload',
        'mime'=>'jpg',
        'multiple', 
    ],
    ['type'=>'close']
]);

对form操作

<?php 
$vue->method("save"," 
let url = '/dry/index/do_add';
if(this.form.id){
    url = '/dry/index/do_edit';
}
ajax(url,this.form,function(res){
    ".vue_message()."
    if(app.code == 0){
        app.load_filter_list();
    }
});
");
$vue->method("close"," 
this.is_add = false;
");
?> 

ajax


public function cascader(){
    $d = \element\form::get_city(); 
    return json_success(['data'=>$d]);
}

public function autocomplete(){
    $arr[] = ['id'=>1,'value'=>'test'];
    $arr[] = ['id'=>2,'value'=>'test22'];
    return json($arr);
}

sku

think_vue_media($vue,"
if(app.upload_spec_field == 'sku'){
    for(let i in dd){
        if(dd[i] && dd[i].url){
            this.form[this.upload_spec_field][this.upload_spec_index].img = dd[i].url;   
            return;       
        } 
    }   
}"," 
    this.selected_media_use_muit = false; 
");

效果

在NetteAdmin中使用

控制器

AdminWithController 是兼容门店后台功能,当继承此类时需要配置

protected $auth = ['admin','store'];

$auth属性默认是 admin,可修改为 store 或 [‘admin’,’store’]

其中 admin表示管理员权限,store表示门店权限。

<?php 
namespace app\kefu\controller;
 
use app\AdminController; 
use hg\apidoc\annotation as Apidoc; 
/**
* @Apidoc\Title("API 客服管理")
*/
class Admin extends AdminController
{  
    use \app\CRUD;
    //protected $ignore_auth  = true;
    protected $auth_name  = 'novel_chapter';
    protected $table  = 'kefu_user';
    protected $validate_add  = 'app\kefu\validate\User.add';
    protected $validate_edit = 'app\kefu\validate\User.edit';
    protected $field  = [
        'name',
        'avatar_url', 
        'user_id',  
    ];
    /**
    * 分页条件查寻
    */
    protected function pager_where(&$where,$input = []){}
    /**
    * 分页每行数据
    */
    protected function get_row(&$v){}
    /**
    * init 前
    */
    protected function before_init(){}
    /**
    * 写入数据前
    */
    protected function insert($data){}
    /**
    *写入数据后
    */
    protected function after_insert($data,$id){}
    /**
    * 更新数据前
    */
    protected function update($data,$id){}
    /**
    * 更新数据后
    */
    protected function after_update($data,$id){}
    /**
    * 删除前
    */
    protected function del($id){}
    /**
    * 删除后
    */
    protected function after_del($id){} 
  
    protected function form(){  
      $form = get_kefu_user_form_field(); 
      return $form; 
    }
      
}

验证类

https://doc.thinkphp.cn/v8_0/rule_buildin.html

<?php 
namespace app\kefu\validate; 
class User extends \FormValidate
{
    protected $rule = [ 
        'name'  =>  'require', 
        'user_id'  =>  'require', 
    ];
  
    protected $message  =   [
        'name.require'    => '客服名必须',  
        'user_id.require' => '第三方用户ID必须',  
    ];
  
    protected $scene = [
        'add'  =>  ['name','user_id'],
        'edit' =>  ['name','user_id'], 
    ];    
  
    public function form_validate_field(){ 
        return get_kefu_user_form_field();
    } 
}

VUE

$vue->method("save()","
    const loading = this.\$loading({
      lock: true,
      text: '处理中,请稍等',
      spinner: 'el-icon-loading',
      background: 'rgba(0, 0, 0, 0.7)'
    });
    this.form.tag = 'blog';
    if(this.form.id){
        $.post('/blog/blog/do_edit',this.form,function(res){
            ".vue_message()."
            if(res.code == 0){
                app.is_open = false;
                app.get_lists();
            }
            loading.close();
        },'json'); 
    }else{
        $.post('/blog/blog/do_add',this.form,function(res){
            ".vue_message()."
            if(res.code == 0){
                app.is_open = false;
                app.get_lists();
            }
            loading.close();
        },'json'); 
    }
       
");

composer源

composer global require slince/composer-registry-manager

composer repo:ls

composer repo:use composer

autoloader后手动添加

global $autoloader;
$autoloader = require __DIR__ . '/../vendor/autoload.php';
$autoloader->addPsr4('app\\', __DIR__.'/../app');

上传、下载

上传

配置支持的后缀

# 上传相关
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