美文网首页
PHP 从菜鸟到大咖的踩坑之路

PHP 从菜鸟到大咖的踩坑之路

作者: smallsha | 来源:发表于2021-05-25 10:35 被阅读0次

    https://cloud.tencent.com/developer/article/1464655 电商Sku设计思维

    https://xlswriter-docs.viest.me/zh-cn/an-zhuang/mac 借助C扩展来 处理百万 excel文件的导入导出

    https://juejin.im/post/6867433557313863688 数组巧用

    https://juejin.im/post/6844904093735976974 来源不一样的数据分页

    https://juejin.im/post/6844904180834893832 curl_multi并发请求

    https://juejin.im/post/6844903849132556296 排查系统为啥会运行缓慢

    https://juejin.im/post/6844904194734817287 本地环境搭建 docker

    个人微信消息推送 http://sc.ftqq.com/?c=code

    #php调用代码
    file_get_contents('https://sc.ftqq.com/SCU144549Te2356489fe44a621fd109f8f7484e9dd5ff2878ccf662.send?text=not_complete_sync_order订单同步失败');
    
    function sc_send(  $text , $desp = '' , $key = 'SCU144549Te2356489fe44a621fd109f8f7484e9dd5ff2878ccf662'  )
    {
        $postdata = http_build_query(
        array(
            'text' => $text,
            'desp' => $desp
        )
    );
    
    $opts = array('http' =>
        array(
            'method'  => 'POST',
            'header'  => 'Content-type: application/x-www-form-urlencoded',
            'content' => $postdata
        )
    );
    $context  = stream_context_create($opts);
    return $result = file_get_contents('https://sc.ftqq.com/'.$key.'.send', false, $context);
    
    }
    

    时间范围

    //获取今日开始时间戳和结束时间戳
     $start = mktime(0,0,0,date('m'),date('d'),date('Y'));
     $end = mktime(0,0,0,date('m'),date('d')+1,date('Y'))-1;
     //获取昨日起始时间戳和结束时间戳
     $beginYesterday = mktime(0,0,0,date('m'),date('d')-1,date('Y'));
     $endYesterday = mktime(0,0,0,date('m'),date('d'),date('Y'))-1;
     //获取上周起始时间戳和结束时间戳
     $beginLastweek = mktime(0,0,0,date('m'),date('d')-date('w')+1-7,date('Y'));
     $endLastweek = mktime(23,59,59,date('m'),date('d')-date('w')+7-7,date('Y'));
     //获取本月起始时间戳和结束时间戳
     $beginThismonth=mktime(0,0,0,date('m'),1,date('Y'));
     $endThismonth=mktime(23,59,59,date('m'),date('t'),date('Y'));
    strtotime(date('Y-m-d 9:30:00',time()));  
    

    laravel whereor 查询

    $extra = $params['extra'];
            $handle->where(function ($query) use ($extra) {
                $query->where('admin_name', 'like', "%$extra%")->orWhere('title', 'like', "%$extra%");
            });
    

    array_walk 和 array_map && array_reduce && array_filter && array_flip 使用

    #array walk以引用传递的形式遍历你的数组,没有返回值,而且只能处理一个数组
    $arr = ['a', 'b', 'c'];
    
    array_walk($arr, function (&$item) {
        $item = $item . '_i';
    });
    print_r($arr); // ['a_i', 'b_i', 'c_i'];
    
    #array_map 使用匿名函数的方式,处理数组里的每个元素。遍历完成后返回一个新的数组,并且可以同时处理多个数组
    $arr_1 = ['a', 'b', 'c'];
    $arr_2 = ['你', '好', '吗', '原', '罪'];
    
    $arr = array_map(function ($item_1, $item_2) {
        return $item_1 . '_' . $item_2 . '_i';
    }, $arr_1, $arr_2);  如果需要获取下标的可以使用 array_keys($arr_1)代替$arr_2
    
    print_r($arr); // ['a_你_i', 'b_好_i', 'c_吗_i', '_原_i', '_罪_i']
    
    #array_reduce() 函数向用户自定义函数发送数组中的值,并返回一个字符串。
      $arr = [
         0 => '全部',
         1 => 'a',
         2 => 'b',
         3 => 'c',
        ];
    $index   = 0;
    $options = array_reduce($arr, function($carry, $item) use (&$index){
        ## $index则为当前两个元素 $item 的索引
        return $carry . '<option value="' . $index++ . '">' . $item . '</option>';
    }, '');
    
    var_dump($options);return;
    #过滤数组中的内容
       $data = [
        [ 'id' => 1, 'name' => '你好,234', 'cate' => '生活日记'],
        [ 'id' => 2, 'name' => '79798', 'cate' => '摄影美图'],
        [ 'id' => 3, 'name' => '567567', 'cate' => '生活日记'],
       ];
    
    $filtered = array_filter($data, function($item){
        return $item['cate'] !== '摄影美图';
    });
    print_r($filtered);return;
    
    #翻转数组去重
    array_flip (array_flip($trans)); 
    #移除数组中重复的值:
    array_unique($arr);   
    #array_flip  和 array_unique区别 array_flip 会保留重复值最后一个,array_unique 只保留重复值的第一个
    
    

    数组遍历思想

    ==数组嵌套循环的时候最内层的遍历完之后指针为空才开始向外层一层一层遍历直到指针遍历完改层数组==

    ==foreach()嵌套foreach都会先把本身{}内的循环完,再进行下一次循环,从里往外开始==

    ==数组元素多的嵌套数组元素少的。小建议==

    ==循环从上往下 从左往右。循环套循环的,程序执行到里面一次要循环完了,外面的才会进行第二次循环==

    php处理大数文件问题

    尽可能使用文件操作,不要直接导入到数组库,过程很慢

    php操作大数组减少内存方法

    <?php
    $start_mem = memory_get_usage();
    function yield_range( $start, $end ){
      while( $start <= $end ){
        $start++;
        yield $start;
      }
    }
    foreach( yield_range( 0, 9999 ) as $item ){
      echo $item.',';
    }
    $end_mem = memory_get_usage();
    echo " use mem : ". ( $end_mem - $start_mem ) .'bytes'.PHP_EOL;
    
    # 操作大文件 
    <?php
    header("content-type:text/html;charset=utf-8");
    function readTxt()
    {
        # code...
        $handle = fopen("./test.txt", 'rb');
    
        while (feof($handle)===false) {
            # code...
            yield fgets($handle);
        }
    
        fclose($handle);
    }
    
    foreach (readTxt() as $key => $value) {
        # code...
        echo $value.'<br />';
    }
    
    
    

    mysql 常用查询

    导出数据表结构说明

    //首先选择mysql里面的information_schema库
    SELECT 
        COLUMN_NAME 字段名称,
        COLUMN_TYPE 数据类型,
        IS_NULLABLE 是否为空,
        COLUMN_COMMENT 字段描述 
    FROM
    COLUMNS 
    WHERE
        TABLE_NAME = 'fr_activity_component' group by COLUMN_NAME ORDER BY ORDINAL_POSITION
    //执行后导出excel
    

    修改一个字段为随机数

    update fr_topic set post_num = ceiling(rand()*3000+9000) WHERE  1=1 
    

    时间戳转换

    FROM_UNIXTIME(a.end_time) 格式化时间
    
    UNIX_TIMESTAMP('2006-11-04 12:23:00'); 格式化成时间戳
    

    把查询出来的一个结果集的sql 某个字段用标识符分割

    SELECT  GROUP_CONCAT(a.`sku_id` separator ',;cc') 账号 from fr_goods_sku a LEFT JOIN fr_goods b  on a.goods_id =b.goods_id where b.type = 1 AND sku_image_url !='' limit 20;
    

    子查询操作

    DELETE from fr_users_bargain where user_id  IN (SELECT user_id from (SELECT user_id,count(slash_id) as ids FROM fr_users_bargain  where cate = 2 GROUP BY user_id HAVING ids > 1) ee)
    

    json 问题 中文和反斜杠被转义

    json_encode($post_data,JSON_UNESCAPED_SLASHES|JSON_UNESCAPED_UNICODE)
    

    curl请求问题排查

      $response = curl_exec($ch);
      $errorno = curl_errno($ch);
      $httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
    

    先根据 curl_errno 查看状态码 然后去
    https://www.php.net/manual/zh/function.curl-errno.php 查看状态码的对应报错

    读取大文件

    读取大文件方法
    <?php
     function yieldCommand($fileName) {
     $line = [];
     $handle = fopen($fileName, "r"); 
         while (!feof($handle)) {
            yield ltrim(fgets($handle));
         } 
         fclose($handle); 
     } 
     foreach (yieldCommand("name.txt") as $key => $value) {
         echo $value; 
     } 
     require "memory.php"; ?>
    
    

    安装pcntl

    https://icharle.com/macpcntl.html

    sudo wget https://www.php.net/distributions/php-7.1.26.tar.gz

    tar -zxvf php-7.1.26.tar.gz

    cd php-7.1.26 && cd ext && cd pcntl

    /Applications/MAMP/bin/php/php7.1.26/bin/phpize php --ini 找到安装的php路径 使用里面的 phpize 在pcntl目录下执行

    /configure --with-php-config=/Applications/MAMP/bin/php/php7.1.2/bin/php-config

    make && make install

    php --ri swoole

    php -i | grep php.ini

    sudo wget https://www.php.net/distributions/php-7.3.7.tar.gz

    数组操作

    if (!function_exists('hideStr')) {
    
        /**
         * [hideStar 用户名、邮箱、手机账号中间字符串以*隐藏]
         * @param  [string] $str [传过来字符串]
         * @return [string]      [返回带*字符串]
         */
        function hideStr($str)
        {
            if (strpos($str, '@')) {
                $email_array = explode("@", $str);
                $prevfix = (strlen($email_array[0]) < 4) ? "" : substr($str, 0, 3);
                $count = 0;
                $str = preg_replace('/([\d\w+_-]{0,100})@/', '***@', $str, -1, $count);
                $rs = $prevfix . $str;
            } else {
                $pattern = '/(1[3458]{1}[0-9])[0-9]{4}([0-9]{4})/i';
                if (preg_match($pattern, $str)) {
                    $rs = preg_replace($pattern, '$1****$2', $str);
                } else {
                    $rs = substr($str, 0, 3) . "***" . substr($str, -1);
                }
            }
            return $rs;
        }
    }
    
    if (!function_exists('format_timestamp')) {
        function format_timestamp($timestamp, $format = "Y.m.d H:i:s")
        {
            return $timestamp <= 0 ? '-' : date($format, (int)$timestamp);
        }
    }
    
    if (!function_exists('get_countdown_second')) {
        function get_countdown_second($time)
        {
            return $time - time() < 0 ? 0 : $time - time();
        }
    }
    
    
    if (!function_exists('get_countdown_second')) {
        function number_format($number, $flag = 2)
        {
            return sprintf("%" . $flag . "f", $number);
        }
    }
    
    
    /**
     * 保留几位小数,向下取整
     *$num 要处理的浮点数
     *$digits 要保留的小数位数
     * 实现思路:先乘以10的小数位数次方,用floor向下取整,再除以除数得到舍去后面位数的结果
     * 最后再用sprintf配合位数再取一次值(此处是为了解决有些数字属,最后一位为零时不显示问题)
     */
    if (!function_exists('floorFloat')) {
        function floorFloat($num, $digits)
        {
            $num = floatval($num);
            $multiple = pow(10, $digits);
            $tempNum = floor($num * $multiple);
            return sprintf('%.' . $digits . 'f', $tempNum / $multiple);
        }
    }
    
    二维数据进行排序
    if(!function_exists('arraySequence')){
        /**
         * 二维数组根据字段进行排序
         * @params array $array 需要排序的数组
         * @params string $field 排序的字段
         * @params string $sort 排序顺序标志 SORT_DESC 降序;SORT_ASC 升序
         */
        function arraySequence($array, $field, $sort = 'SORT_ASC')
        {
            $arrSort = array();
            foreach ($array as $uniqid => $row) {
                foreach ($row as $key => $value) {
                    $arrSort[$key][$uniqid] = $value;
                }
            }
            array_multisort($arrSort[$field], constant($sort), $array);
            return $array;
        }
    }
    
    
    
    
    二维数组转一维数组   array_column();
    
    二维数组去重
    
    function remove_duplicate($array){
      $result=array();
      foreach ($array as $key => $value) {
        $has = false;
        foreach($result as $val){
          if($val['id']==$value['id']){
          $has = true;
          break;
        }
      }
    if(!$has)
      $result[]=$value;
    }
    return $result;
    }
    
    过滤一个数组在另一个数组中出现的 。
    var arr1 = ["i", "b", "c", "d", "e", "f","x"]; //数组A  
    var arr2 = ["a", "b", "c", "d", "e", "f", "g"];//数组B  
    
    var temp = []; //临时数组1  
    var temparray = [];//临时数组2  
    for (var i = 0; i < arr2.length; i++) {  
        temp[arr2[i]] = true;//巧妙地方:把数组B的值当成临时数组1的键并赋值为真  
    }
    for (var i = 0; i < arr1.length; i++) {  
        if (!temp[arr1[i]]) {  
            temparray.push(arr1[i]);//巧妙地方:同时把数组A的值当成临时数组1的键并判断是否为真,如果不为真说明没重复,就合并到一个新数组里,这样就可以得到一个全新并无重复的数组  
        } 
    }
    document.write(temparray.join(",") + ""); 
    
    
    
    /*
     * 计算倒计时
     * @param unix时间格式
     * @return string
     */
    function dealTime($endTime) {
    
        $t = $endTime - time();
    
    
        if ($t <= 0) return '';
    
        $str = '';
    
        if ($t > 86400) {
            $days = floor($t / 86400);
            
            $t = $t - (86400 * $days);
            $str .= $days . '天';
        } 
     
    
        if ($t > 3600) {
            $hours = floor($t / 3600);
            $t = $t - (3600 * $hours);
            $str .= $hours . '时';
        }
    
        if ($t > 60) {
            $minu = floor($t / 60);
            $t = $t - (60 * $minu);  
            $str .= $minu  . '分';
        }
    
        $str .= $t . '秒';
    
        return $str;
    }
    
    /**
     * 隐藏部分电话号码,手机号隐藏中间四位
     * @param strint $phone
     * @return string
     */
    function hidetel($phone){
        $IsWhat = preg_match('/(0[0-9]{2,3}[-]?[2-9][0-9]{6,7}[-]?[0-9]?)/i', $phone); //固定电话
        if ($IsWhat == 1) {
            return preg_replace('/(0[0-9]{2,3}[-]?[2-9])[0-9]{3,4}([0-9]{3}[-]?[0-9]?)/i','$1****$2', $phone);
        } else {
            return  preg_replace('/(1[35678]{1}[0-9])[0-9]{4}([0-9]{4})/i','$1****$2', $phone);
        }
    }
    
    /**
     * 随机生成颜色值
     * 
     * 
     */
    function randcol() 
    { 
      $str='0123456789ABCDEF'; 
        $estr='#'; 
        $len=strlen($str); 
        for($i=1;$i<=6;$i++) 
        { 
            $num=rand(0,$len-1);   
            $estr=$estr.$str[$num];  
        } 
        return $estr; 
    }
    
    /**
     * 将xml转为array
     * @param  string   $xml xml字符串或者xml文件名
     * @param  bool     $isfile 传入的是否是xml文件名
     * @return array    转换得到的数组
     */  
    function xmlToArray($xml,$isfile=false){
        //禁止引用外部xml实体  
        libxml_disable_entity_loader(true);
        if($isfile){
            if(!file_exists($xml)) return false;
            $xmlstr = file_get_contents($xml);
        }else{
            $xmlstr = $xml;
        }
        $result= json_decode(json_encode(simplexml_load_string($xmlstr, 'SimpleXMLElement', LIBXML_NOCDATA)), true);
        return $result;
    }  
    
    
    /**
     * 数组转xml字符
     * @param  string   $xml xml字符串
     **/  
    function arrayToXml($data){
        if(!is_array($data) || count($data) <= 0){
            return false;
        }
        $xml = "<xml>";
        foreach ($data as $key=>$val){
            if (is_numeric($val)){
                $xml.="<".$key.">".$val."</".$key.">";
            }else{
                $xml.="<".$key."><![CDATA[".$val."]]></".$key.">";
            }
        }
        $xml.="</xml>";
        return $xml;
    

    htmlspecialchars,strip_tags 来过滤html,js 代码

    设计模式

    
    __get  __call  abstract 灵活运用实例 编写通用SDK
    1.利用__get获取没有定义的变量然后来通过__call调用未知方法
    2.abstract 的子类定义的变量 是可以覆盖 父类的定义的变量
    3.abstract 里面放子类里面公用的代码
    
    $shopify = PHPShopify\ShopifySDK::config($config);
    
    $products = $shopify->Product->get(['fields'=>'id,images,title']);
    
    public static $config = array(
    );
    public function __construct($config = array())
    {
        if(!empty($config)) {
            ShopifySDK::config($config);
        }
    }
    
    
    public function __get($resourceName)
    {
        return $this->$resourceName();
    }
    
        
    public function __call($resourceName, $arguments)
    {
    if (!in_array($resourceName, $this->resources)) {
        if (isset($this->childResources[$resourceName])) {
            $message = "$resourceName is a child resource of " . $this->childResources[$resourceName] . ". Cannot be accessed directly.";
        } else {
            $message = "Invalid resource name $resourceName. Pls check the API Reference to get the appropriate resource name.";
        }
        throw new SdkException($message);
    }
    
        $resourceClassName = __NAMESPACE__ . "\\$resourceName";
        
        //If first argument is provided, it will be considered as the ID of the resource.
        $resourceID = !empty($arguments) ? $arguments[0] : null;
        
        //Initiate the resource object
        $resource = new $resourceClassName($resourceID);
        
        return $resource;
    }
    
    
    abstract class ShopifyResource{
        
           /**
         * @inheritDoc
         */
        public $resourceKey;
    
        /**
         * @inheritDoc
         */
        protected $childResource;
    
        public function __construct($id = null, $parentResourceUrl = '')
        {
            $this->id = $id;
        
            $config = ShopifySDK::$config;
        
        }
    }
    
    class Product extends ShopifyResource
    {
        /**
         * @inheritDoc
         */
        public $resourceKey = 'product';
    
        /**
         * @inheritDoc
         */
        protected $childResource = array(
            'ProductImage' => 'Image',
            'ProductVariant' => 'Variant',
            'Metafield',
            'Event'
        );
    }
    
    
    
    
    
    
    
    
    
    <?php
    /**
     * 事件产生类
     * Class EventGenerator
     */
    abstract class EventGenerator
    {
        private $ObServers = [];
    
        //增加观察者
        public function add(ObServer $ObServer)
        {
            $this->ObServers[] = $ObServer;
        }
    
        //事件通知
        public function notify()
        {
            foreach ($this->ObServers as $ObServer) {
                $ObServer->update();
            }
        }
    
    }
    
    /**
     * 观察者接口类
     * Interface ObServer
     */
    interface ObServer
    {
        public function update($event_info = null);
    }
    
    /**
     * 观察者1
     */
    class ObServer1 implements ObServer
    {
        public function update($event_info = null)
        {
            echo "观察者1 收到执行通知 执行完毕!\n";
        }
    }
    
    /**
     * 观察者1
     */
    class ObServer2 implements ObServer
    {
        public function update($event_info = null)
        {
            echo "观察者2 收到执行通知 执行完毕!\n";
        }
    }
    
    /**
     * 事件
     * Class Event
     */
    class Event extends EventGenerator
    {
        /**
         * 触发事件
         */
        public function trigger()
        {
            //通知观察者
            $this->notify();
        }
    }
    
    //创建一个事件
    $event = new Event();
    //为事件增加旁观者
    $event->add(new ObServer1());
    $event->add(new ObServer2());
    //执行事件 通知旁观者
    $event->trigger();
    

    Yii框架

    多图上传
    https://blog.csdn.net/zbc496218/article/details/51442051

    值得学习博客: http://www.yiichina.com/extension/1206

    中文文档 http://www.yii-china.com/doc/guide/structure_widgets.html
    白狼寨

    GridView http://blog.csdn.net/myhuashengmi/article/details/53386206

    use common\widgets\ImgMultUpload;
    <?= ImgMultUpload::widget(['label' => '产品图片', 'imgarr'=>['12321.jpg'],'imagedir' => '/uploads/temp/']); ?>
    
    
    引入类方法:
    ①Yii::$classMap['类名']=>'@app/libs/文件名';映射类,在controller中调用
    use 类名;可立即使用;此类中不需要写 namespace
    ②在config数组中加入 aliases=>['@test'=>@app/文件夹];test代表后面的链接,别名引入类。use 别名\类名;可立即使用。  此类中需要写 namespace
    
    打印当前所执行的sql
    echo $query->createCommand()->getRawSql();die;
    
    params文件夹中配置写经常变化的内容:  key =>value 形式展示
    Yii::$app->param['key']获取参数value值。
    
    composer安装yii框架   安装好之后进入yii框架中进行composer install 安装vendor目录
    controller操作注意:
     请求参数:   $request=Yii:$app->request;   $request->get(); $request->post();
                 $request->bodyParams();可以获取任何类型以及所有的参数
                 $request->getBodyParam('id')特定的获取某个参数
     render    renderPartial不会渲染模板。 
    注意事项:
    ①模型类,需引入use Yii;ActiveRecord类用。
    
    Controller声明需要注意 actionIndex  方法名必须是驼峰式的,action来声明是可以跳转的方法
    
    migrate生成数据库
    ① 在根目录生成migrations 目录生成对应的文件 yii  migrate/create test
    ②修改test文件,中间引入 yii\db\Schema,利用Schema来生成表的和结构
    ③最后使用 yii migrate 来生成对应的数据库。
    
    
    yii框架中设置别名
    在web.php 里面  设置 Yii::setAlias('@bar','www.baidu.com');
                     取出Yii::getAlias('@bar');
    
    
    gii,debug访问不到,原因可能是继承Controller,默认访问的是r=index,所以导致路由不到。
    
    美化url:  将urlmanager 写到components数组中 (此方法暂时不能正常使用)
    
    'urlManager' => [
        'enablePrettyUrl' => true,  //是否启用美化url pathinfo 模式
        //就必须添加扩展名
        'showScriptName' => false,  //是否显示脚本名
        'rules' => [
        ],
    ],
    使用以上的方法UrlManager控制路由,导致Url::to([]);方法不能正常使用,解决办法:
    在入口文件平级目录创建.htaccess 文件,内容如下:
    Options +FollowSymLinks
    IndexIgnore */*
    RewriteEngine on
    
    # if a directory or a file exists, use it directly
    RewriteCond %{REQUEST_FILENAME} !-f
    RewriteCond %{REQUEST_FILENAME} !-d
    
    # otherwise forward it to index.php
    RewriteRule . index.php
    
    
    yii-debug
    
    显示在页面中加<?php $this->endBody;?>,将显示xdebug
    原理:  yii\web\View 中有 endBody 的触发事件,回去触发bootstarp,注册插件,从而将大量的debug样式加载到页面 上,图标因此出现。
    
    时区显示不正确,在web.config中添加 'timeZone' => 'Asia/Shanghai',
    
    
    __DIR__ 当前目录 不包含文件名字 dirname(__DIR__) 当前目录的 dir 
    例如:E:\project\yii\controllers                 E:\project\yii
    
    __FILE__  当前文件路径  包含文件名字 dirname(__FILE__) 所包含当前文件的文件夹
    例如:E:\project\yii\controllers\IndexController.php            E:\project\yii\controllers
    
    配置空页面的跳转方法    web.php中配置的有。
    'errorHandler' => [
        'errorAction' => 'site/error',
    ],
    
    
    控制器中需要声明下 public function actions()
    {
        return [
            'error' => [
                'class' => 'yii\web\ErrorAction',
            ],
        ];
    }  
    访问的页面不在的话就 跳转到该视图  ,将此封装到基础控制器中减少代码
    
    设置方法返回格式  
    Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
    
    组件component 
    在配置文件component中加 key => 类的命名空间,注册后才用Yii::$app-> key->类中方法。即可实现全局访问的效果。
    
    
    多数据库链接(判别当前数据库)
    /**
     * 设置模型获取数据库链接
     * */
    public static function getDb(){
        return Yii::$app->get('db_spkx');
    }
    
    

    google 插件

    jsonview 滑词翻译 apizza octotree Infinity wappalyzer gitpod

    Infinity 账号 2233850112@qq.com 14adb1

    composer

    composer config repo.packagist composer https://mirrors.aliyun.com/composer 阿里云源

    composer config repo.packagist composer https://packagist.phpcomposer.com composer局部声明源

    composer selfupdate 更新phar.

    https://github.com/zoujingli/ThinkAdmin 通用后台开发框架

    https://github.com/geesondog/rhaphp 结合tp5微信开发

    https://demo.fastadmin.net 结合tp5后台快速开发(插件化 收费)

    https://tencent.github.io/wepy/ 开发小程序框架


    composer 命令大全
    https://getcomposer.org/doc/03-cli.md#global-options

    常用composer 库

    composer require nesbot/carbon 时间间隔

    composer require guzzlehttp/guzzle curl 请求

    composer require yansongda/pay 微信支付包 riverslei/payment

    composer require katzgrau/klogger:dev-master 处理日志类

    "phpoffice/phpword": "v0.13.*" 生成word 文件

    composer require league/fractal 复杂输出ajax 和restful

    composer require phpmailer/phpmailer 邮件处理类

    账号 15239851762@163.com 163 测试 发送密码填写 smtp 的授权密码 smallsha666 端口 465

    composer require overtrue/easy-sms 短信处理类

    https://segmentfault.com/a/1190000007411281 图片处理类

    filp/whoops

    catfan/medoo

    twig/twig

    sysfony


    composer操作

    composer depends ak_smallsha/application -t

    获取当前composer中的有关当前包的扩展

    composer config --list 查看当前包的配置信息

    composer search 包 查询composer中包

    composer show aferrandini/* 查询当前项目中的包

    composer clear-cache 下载包出现问题首先执行该命令

    composer init --require = ak_smallsha/application -n

    创建一个新的composer.json包并且添加依赖

    可能的少使用comoser update -vvv 导致更新最新版本,项目不兼容。
    每次引入类库后,将composer.json和composer.lock 上传到github上。

    composer dump-autoload -o 之后,composer
    就会提前加载需要的类并提前返回。这样大大减少了 IO 和深层次的 loop。

    composer clear-cache 清除缓存

    composer install - 如有 composer.lock 文件,直接安装,否则从
    composer.json 安装最新扩展包和依赖;

    composer update - 从 composer.json 安装最新扩展包和依赖;

    composer update vendor/package - 从 composer.json 或者对应包的配置,并更新到最新;

    composer require new/package - 添加安装 new/package, 可以指定版本,如: composer require new/package ~2.5.

    代码上传到packlist https://www.cnblogs.com/zhangwei595806165/p/5814476.html
    http://blog.csdn.net/hel12he/article/details/46659749 在packlist自动更新github上的包

    发布自己的composer包

    composer是什么
    Composer 不是一个包管理器。是的,它涉及 “packages” 和 “libraries”,但它在每个项目的基础上进行管理,在你项目的某个目录中(例如 vendor)进行安装。默认情况下它不会在全局安装任何东西。因此,这仅仅是一个依赖管理。
    Composer 受到了 node’s npm 和 ruby’s bundler 的强烈启发。而当时 PHP 下并没有类似的工具。
    composer可以做什么
    Composer 将这样为你解决问题:
    你有一个项目依赖于若干个库。
    其中一些库依赖于其他库。
    你声明你所依赖的东西。
    Composer 会找出哪个版本的包需要安装,并安装它们(将它们下载到你的项目中)。
    系统学习composer的使用请移步 composer中文学习
    开发自己的composer组件
    要点:理解composer如何实现自动加载第三方组件; 理解psr-0和psr-4的规范; 理解基于psr-0,psr-4,classmap,files如何实现自动加载。 理解Composer和Packagist
    关于安装和使用composer请参考composer中文学习
    创建目录名称
    mkdir try-make-package
    cd try-make-package
    这个try-make-package文件夹就是你的包的根目录了,你只需要记住composer.json在包的哪个目录下面,一般那就是包的根目录了。
    现在我们还没有composer.json文件,下面我们来初始化
    初始化扩展包
    ☁  composer init
      Welcome to the Composer config generator
    This command will guide you through creating your composer.json config.
    Package name (<vendor>/<name>) [lingan/try-make-package]:
    Description []: try make a package
    Author [saboran <saboran@163.com>, n to skip]:
    Minimum Stability []: dev
    Package Type (e.g. library, project, metapackage, composer-plugin) []: library
    License []: MIT
    Define your dependencies.
    Would you like to define your dependencies (require) interactively [yes]? n
    Would you like to define your dev dependencies (require-dev) interactively [yes]? n
    {
        "name": "lingan/try-make-package",
        "description": "try make a package",
        "type": "library",
        "license": "MIT",
        "authors": [
            {
                "name": "saboran",
                "email": "saboran@163.com"
            }
        ],
        "minimum-stability": "dev",
        "require": {}
    }
    Do you confirm generation [yes]? yes
    经过一番上面的挣扎在当前目录就生成了composer.json文件,下面我们对这个文件进行一些修改
    修改composer.json增加自动加载规范(命名空间和目录映射关系)和环境要求
    {
      "name": "lingan/try-make-package",
      "description": "try make a package",
      "type": "library",
      "license": "MIT",
      "authors": [
        {
          "name": "saboran",
          "email": "saboran@163.com"
        }
      ],
      "minimum-stability": "dev",
      "require": {
        "php": ">=7.0"
      },
      "autoload": {
        "psr-4": {
          "Flower\\Rose\\": "src/Flower/Rose",
          "Flower\\Lily\\": "src/Flower/Lily"
        }
      }
    }
    创建类文件
    根据上面的命名空间和目录的映射关系,创建对应目录和文件,如下图
    
    对应文件内容
    <?php
    /**
     * Created by PhpStorm.
     * User: Lingan
     * Date: 2017/11/6
     * Time: 21:39
     */
    namespace Flower\Rose;
    class Rose
    {
        public function desc()
        {
            echo "this is rose flower";
        }
    }
    <?php
    /**
     * Created by PhpStorm.
     * User: Lingan
     * Date: 2017/11/6
     * Time: 21:38
     */
    namespace Flower\Lily;
    class Lily
    {
        public function desc()
        {
            echo "this is lily flower";
        }
    }
    测试安装
    以上代码都梳理完毕后,需要composer install来测试我们的包是否可以正常工作此时会在vendor/composer/autoload_psr4.php中生成命名空间和目录的映射关系,被包在一个数组中:
    <?php
    // autoload_psr4.php @generated by Composer
    $vendorDir = dirname(dirname(__FILE__));
    $baseDir = dirname($vendorDir);
    return array(
        'Flower\\Rose\\' => array($baseDir . '/src/Flower/Rose'),
        'Flower\\Lily\\' => array($baseDir . '/src/Flower/Lily'),
    );
    增加.gitignore为git忽略一些文件,增加readme.md为项目增加描述
    .idea
    vendor/
    composer.lock
    提交代码到github
    现在自己的Github主页上创建一个新的仓库然后将项目提交到对应仓库,参考如下
    git init
    git add -A
    git commit -am "init && dev package"
    git remote add origin git@github.com:linganmin/try-make-package.git
    git push -u origin master
    
    登录自己的packagist submit(自己注册)
    将自己的项目地址粘贴
    
    
    点击check,然后点击submit,至此,自己的composer包就提交成功了,
    
    测试使用自己开发的包扩展[2017.11.07更新]
    创建测试目录
    mkdir test-my-package
    cd test-my-package
    安装自己的扩展
     composer require lingan/try-make-package dev-master
    ./composer.json has been updated
    Loading composer repositories with package information
    Updating dependencies (including require-dev)
    Package operations: 1 install, 0 updates, 0 removals
      - Installing lingan/try-make-package (dev-master d7b9f94): Cloning d7b9f941b0 from cache
    Writing lock file
    Generating autoload files
    安装完成的目录如下图
    
    查看autoload_psr4.php
    <?php
    // autoload_psr4.php @generated by Composer
    $vendorDir = dirname(dirname(__FILE__));
    $baseDir = dirname($vendorDir);
    return array(
        'Flower\\Rose\\' => array($vendorDir . '/lingan/try-make-package/src/Flower/Rose'),
        'Flower\\Lily\\' => array($vendorDir . '/lingan/try-make-package/src/Flower/Lily'),
    );
    新建首页入口文件index.php,开始测试自己写的包
    <?php
    /**
     * Created by PhpStorm.
     * User: Lingan
     * Date: 2017/11/7
     * Time: 11:04
     */
    require_once './vendor/autoload.php'; // 加载自动加载文件
    use Flower\Rose\Rose;
    use Flower\Lily\Lily;
    $rose = new Rose();
    $lily = new Lily();
    echo $rose->desc();
    echo "\n";
    echo $lily->desc();
    执行
    php index.php
    this is rose flower
    this is lily flower%
    * 至此说明我们自己开发的扩展包可以正常使用
    设置Packagist上自动更新扩展包,即当我们更新扩展包提交到GitHub时,Packagist自动更新
    在没有设置自动更新时,Packagist上包详情页会有这样一个提示
    This package is not auto-updated. Please set up the GitHub Service Hook for Packagist so that it gets updated whenever you push!(这个软件包不是自动更新的。请为Packagist 设置GitHub服务钩,以便在您推送时更新!)
    详细设置自动更新软件包的文档地址
    简化步骤如下:
    去个人中心页面拿到自己的api令牌
    去当前包在GitHub的地址,点击设置,点击集成和服务,点击添加Packagist服务并配置你的API令牌,以及你的Packagist用户名和账号对应域名
    选择active,点击add service
    设置自动更新结束,之后你更改了自己包扩展的代码提交到GitHub后,很短的时间差就会同步到Packagist
    
    

    laravel

    http://laravel-admin.org/ laravel-admin

    https://www.jianshu.com/p/18d3b77a13f3

    数据库迁移
    http://laravelacademy.org/post/130.html

    数据库操作
    http://laravelacademy.org/post/8060.html

    http://blog.csdn.net/ks3ks/article/details/54942816

    权限RBAC
    https://packagist.org/packages/zizaco/entrust#dev-master

    分页
    http://laravelacademy.org/post/8156.html

    项目
    https://www.bandari.net/blog laravel整合workerman

    队列
    http://blog.csdn.net/chen529834149/article/details/78894894

    核心一   Facade   
     方便开发者直接用静态方法调用,加快开发速度,不需要依托服务器容器。
    创建 facade  步骤 1 先写好自己的方法  
     步骤2  编写providers 可以使用  php artisan make:provider 生成服务提供者
    public function register()
    {
    将写好的方法注册到 ajaxResponse;
        $this->app->singleton('ajaxResponse', function () {
            return new \App\Services\ajaxResponse();
        });
    }
    
    步骤3 编写 facades 
    class AjaxResponseFacade extends Facade
    {
        protected static function getFacadeAccessor()
        {
            return 'ajaxResponse';
        }
    }
    
    步骤4 进入config/app.config
    
    在providers 数组中编写  将服务提供者provides ::class 注册进去
    
    步骤5 
    在aliases 中将编写好的门面 放入。方便调用。
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    
    核心二  服务器容器
    服务容器      使用命名空间引入类,然后将名称注入到 __construct或者是方法名中,声明变量,将注入的类指定到变量中,此方法雷同于yii框架的组件化。
    
    
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    
    核心三  contracts  契约     主要是减少代码的冗余
    
    ①首先编写一个接口contracts 接口类
    ②在编写自己的要实现功能 implement 继承接口类
    ③开始编写provider ,实现register方法
    public function register()
    {
        //给这个接口一个别名
        $this->app->bind('Hello','App\Contracts\Hello');
        //将Contract接口和它的实现类绑定
        $this->app->bind
        ('App\Contracts\Hello','App\Services\helloWorld');
    
    }
    ④然后将此provider放入到config\app.php中
    ⑤在类中调用使用服务容器的方法进行调用
    
    ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    
    laravel 文档
    博客 http://www.cnblogs.com/itfenqing/category/1010078.html
    小下博客    https://www.linganmin.com/show/59
    韩天峰博客  http://rango.swoole.com/archives/519
    laravle中文手册:http://d.laravel-china.org/docs/5.4     速查: https://cs.laravel-china.org/
    http://laravelacademy.org/post/7930.html   smartApi 项目
    https://github.com/JJJJJJJerk/laravel-passport-admin-stock-loan   laravel5.5 
    =====================================================================
    常用 artisan命令   
    
    php artisan make:controller PhotoController --resource --model=Photo 
    php artisan make:model User -m   生成模型并生成迁移文件
    =====================================================================
    常用blade
    {!! $name !!} 防止xss 攻击
    {{ $name or $hello }}  三元运算符
    
    
    
    =====================================================================
    
    常用组件
    laravel-password oauth2认证 
    https://www.jianshu.com/p/2988ba405b3b?from=timeline&isappinstalled=0
    
    easywechat 网页授权
    https://github.com/overtrue/laravel-wechat
    https://github.com/overtrue
    微信机器人 swoole
    http://create.hanc.cc/vbot/docs/install.html
    
    laravel-debugbar  监控sql和route
    http://laravelacademy.org/post/2774.html   
    默认会将debugbar 添加到页面的body后, 
    \Debugbar::disable(); 关闭
     \Debugbar::enable();开启
    config 里面inject  设置false 禁止渲染页面
    ==================================================================
    常见问题
    base类中获取不到session,原因
    在Laravel以前的版本中,可以在控制器构造函数中获取session变量或者认证后的用户实例。 
    在Laravel 5.3中,在控制器构造函数中不再能够直接获取到session变量或认证后的用户实例,因为中间件还未启动。 
    仍然有替代方案,那就是在控制器构造函数中使用Closure来直接定义中间件。 
    请注意,在使用这个方案的时候,确保你所使用的Laravel版本高于 5.3.4:
    可以在构造方法中采用以下方法获取:
    $this->middleware(function ($request, $next) {
        return $next($request);
    });
    base64 数据流图片解决办法
    $base64_string= explode(',', $base64_string); //截取data:image/png;base64, 这个逗号后的字符
    $data= base64_decode($base64_string[1]);  //对截取后的字符使用base64_decode进行解码
    file_put_contents($url, $data); //写入文件并保存
    
    https://www.cnblogs.com/lyzg/p/6181055.html   app()使用
    https://www.onmpw.com/tm/xwzj/sjk_251.html   mysql 查询判断
    https://segmentfault.com/q/1010000009858793   422 ajax处理
    用户管理系统  php artisan  make:auth  -> php arisan migrate出现数据unique字节数过大,原因laravel 采用utf8mb4 字符,mysql 默认是utf-8. 处理方法在app->provides->appprovide->boot方法下加入    use Illuminate\Support\Facades\Schema;          Schema::defaultStringLength(191);
    
    php artisan vendor:publish  --provider   命令迷惑 
    
    

    swoole

    swoole 博客 包含mac 快捷软件
    https://www.cnblogs.com/redirect/p/7837238.html

    swoole 配置说明
    https://github.com/LinkedDestiny/swoole-doc/blob/master/doc/01.swoole_server%E9%85%8D%E7%BD%AE%E9%80%89%E9%A1%B9.md

    守护进程开启后,关闭采用
    http://blog.csdn.net/qq_33679504/article/details/78659220

    swoole 成员博客
    https://blog.csdn.net/u012979009/article/details/54602935

    pecl 安装swoole 出现sll
    https://stackoverflow.com/questions/31842400/ssl-issue-after-pear-channel-update-pear-php-net

    //nginx 设置第一发包和第二次发包 时间等待
    https://blog.csdn.net/jack______/article/details/76588998

    websocket客户端断开状态码
    https://www.javascriptcn.com/read-30780.html

    注意事项
    
    查看php.ini 位置 php -i|grep php.ini  
    查看是否含有swoole.so  cat /www/server/php/71/etc/php.ini| grep swoole.so
    
    swoole_websocket_server     php  --ri swoole查看php是否支持swoole
    服务器端绑定ip  0.0.0.0  端口需要注意将阿里云的安全策略打开
    客户端绑定ip  39.106.59.83 端口号和服务器端绑定端口号一致
    
    ①代码中不要使用sleep,导致进程堵塞
    ②exit/die,导致woker进程退出
    ③register_shutdown_function  来捕获致命错误
    ④在回调函数中使用try/catch,否则程序异常,不支持set_exception_handler
    ⑤连接redis,mysql类型的连接应该放到OnWorkerStart 回调函数中
    ⑥引入文件 使用include_once,require_once;
    ⑦worker是隔离的,使用swoole_table 将全局变量保存起来。
    ⑧事件回调中所有的局部变量都会全部回收,全局变量需要自己unset
    ⑨global,static,$_GET,$_POST,$GLOBALS 保存在swoole_server 不会自动释放
    ⑩多进程的情况下,父进程使用mt_rand,子进程要使用mt_srand。
    
    server 配置
    dispatch_mode = 7  无论极端条件下任务都会及时处理
    
    

    相关文章

      网友评论

          本文标题:PHP 从菜鸟到大咖的踩坑之路

          本文链接:https://www.haomeiwen.com/subject/nguqsltx.html