1. 不要使用 mysql_ 类函数
    终于,你不用再看到建议不要使用 mysql_ 函数的提示了。因为 PHP 7 从核心上完全移除了它们,这意味着请你移步至更好的 mysqli_ 类函数,或者更灵活的 PDO 层。
  2. 不要写无用的代码
    这看上去是个无脑建议,但是随着 PHP7 速度的提升掩盖了一些问题使它显得日趋重要。不要仅仅因切到 PHP7 让网站速度变得快点,你就沾沾自喜了。

想理解速度的重要性和如何做的更好,去看看我们这篇文章 初学者加速优化指南。

作为开发者,应该确保按需加载脚本,可能时再组合,编写高效的数据库查询语句,如果可能的话 使用缓存 等等。

  1. 不要在文件末尾使用 PHP 闭合标签
    如果你随便看看,就会发现大部分 WordPress 核心代码文件结尾都省略了 PHP 闭合标签。事实上,Zend 框架尤为明显地 禁止了闭合标签。它并非 PHP 所必须,在文件结尾处省略它,可确保结尾无额外空白。
  2. 如非必须不要引用传参
    我个人非常不喜欢引用传参。我当然知道在某些场合下它很有用,但是多数场合下,它会使得代码难以理解,难以遵循,难以预测结果。

人们认为引用可以使它们的代码更快,不过正如 可敬的 PHP 程序员 的这篇文章所指出的,事实并非如此。

PHP 内置的 shuffle() 或者 sort() 函数,就是糟糕的引用传参案例。 它修改了原数组而不是返回一个打乱的或者排好序的数组,这是完全违背了我们意愿的。

  1. 不要在循环里使用查询
    在循环中使用数据库查询时最糟糕的。他会给系统带来不必要的压力,并且很有可能,你可以在循环外使用查询而更快的得到相同的结果。当我碰到必须这样用的场景时,我通常会通过分成两个查询来构造一个数组的方式来解决。然后循环数组而无需循环查询。

由于 WordPress 的运行方式,这样做可能会有些例外。 get_post_meta() 将从数据库获取一个元数据,如果您正在循环访问特定文章的元数据,则可以在循环中使用它。这是因为当你第一次使用它的时候,WordPress 实际上取得了所有的元数据并缓存了起来。 之后的调用实际上是调用缓存数据而不是调用数据库。

解决这些问题的最好办法是阅读函数文档并且使用一些类似 查询监听器 的东西。

  1. 不要在 SQL 查询中使用 *

好吧,这更像是一个 MySQL 的问题,但我们更倾向于在代码中编写 SQL 语句,所以我说这是个公平的游戏。不管什么情况下,如果你能避免使用通配符,那就不要使用,尤其是当你的数据库有很多字段的时候。

明确指定你需要的字段,并且只检索这些字段。这有助于节省内存,保护数据,并且能让事情变得更加清晰明白。

在 SQL 方面,尽可能的了解你可用的函数并测试速度。 当计算平均数,求和以及计算相似的数字的时候,使用 SQL 内置函数而不是 PHP 的函数。 如果你不确定一个查询的速度快慢,测试一下它并和其他做法进行比较,选出最好的那一种。

  1. 不要信任用户的输入
    信任用户输入并不明智。对于用户输入,总是需要过滤,杀毒,转义,校验以及使用回退。 用户输入存在三个问题:我们开发者不可能考虑到所有可能性,经常出错,存心的恶意输入。

一个经过深思熟虑的系统可以防止所有的这些问题。 在使用数据库时,确保使用内置的函数,如 filter_var(),来检查合法性,进行转义,和其他能做的事。

WordPress 有一堆函数可以帮到你。可以瞧一瞧这篇文章来了解更多信息 Validating, escaping and sanitising user data 。

  1. 不要自作聪明
    你的目标就是写出能清晰的表达你的意愿的优雅代码。可能你通过缩短变量名,使用多层级三目逻辑运算和其他小聪明让每个页面节约了0.01秒的加载时间,但是和因此种下你和你的团队头疼不已难以维护的恶果相比,得不偿失。

恰当的命名变量,以简洁明了的方式写出代码文档。更好的做法就是,使用标准化的面向对象的代码风格,或多或少的编写文档,而非使用大量的内联代码注释。

  1. 不要重复造轮子
    PHP 已经存在有一段时间了,网站开发存在的时间甚至更久远。 无论你做过啥,前人肯定已经做过。不要害怕依赖别人的支持, Github, Composer , Packagist 都是你的良师益友。

从日志到颜色处理器,从分析器到单元测试框架,从 Mailchimp APIs 到 Twitter Bootstrap,所有的东西只需要按一个按钮(或者敲一个命令)就能用,去使用它们吧!

  1. 不要忽视其他语言
    如果你是个 PHPer,现在的标准做法是至少了解 HTML,CSS,Javascript 和 MySQL。 当你能很好的处理这些语言的时候,就是再去学习一遍 Javascript 的时候。Javascript 不是 jQuery。你应该学习 Javascript 来有效的利用 jQuery。

我也建议学习 PHP 面向对象的一切。它是个救星,能让你的代码在数量级上得到提升。它也能打开类似 C# 和 Java 语言的大门,在你有了这些经验后,它们能让你更容易明白面向对象编程(OOP)。

通过学习包管理,构建脚本,Coffeescript, LESS, SASS, YAML, 模板引擎以及其他有用的工具来扩展知识面。我也由衷的推荐看看其他框架,尤其是 Laravel 。

当你这些都做得够好了的时候,考虑下 Ruby, Ruby on Rails 以及 Android,iPhone,Windows Phone 的 app 开发? 你可能认为这些毫无意义,因为它们不在你的舒适区和工作需求之内,但它们恰恰是重点。 每种语言都有一些有用的教学知识和一些无害的额外知识。所有顶尖的PHP开发人员都了解其他编程语言,这不是偶然的!

说到IP定位,有百度地图,高德地图,腾讯地图,三者都能通过IP定位得到省市,能得到县城只有腾讯地图,经纬度腾讯和百度比较好用,高德是区域经纬,
这三者中有百度地图和高德地图支持天气查询,只有百度地图有图片显示,高德没有地图三种地图都支持js调用和服务器端调用,建议都用https

在ajax返回值赋值给js全局变量时,全局变量是获取不到的,ajax默认是异步的,当然可以改成同步就能赋值,不过更好解决方法是使用sessionStorage来保存ajax获取的值,在任意地方就可以全局获取.

sessionStorage.setItem('testKey','这是一个测试的value值');

sessionStorage.getItem('testKey');

就这两行代码即可

无限分类是一个很好的分类方法,需要用到三个字段

id pid title 分别是id 父id 分类名称

生成一个无限分类数组,用到了递归,一般开发中分类最多三级,太多也无用处,理论上无限级分类.

function gettree($pid=0,&$result=array(),$spac=0){
    $spac = $spac+2;
    $row = pdo_getall('item',array('pid'=>$pid));
    foreach($row as $v){
        if($v['pid']==0){
            $v['title'] = $v['title'];
        } else{
            $v['title'] = str_repeat('  ',$spac)."|--".$v['title'];
        }


        $result[] = $v;
        gettree($v['id'],$result,$spac);
    }
    return $result;
}

输出分类 传入父类id,默认是从最顶级0开始的,参数2是选中的

function puttree($pid=0,$selected=0){
    $rs = gettree($pid);
    $str='';
    $str .= "<select name='pid'>";
    $str .= '<option value="0">顶级分类</option>';
    foreach($rs as $key=>$val){

        if($val['id'] == $selected){
            $selectedstr = "selected";
        }else{
            $selectedstr = "";
        }
        $str .= "<option $selectedstr value='".$val['id']."'>".$val['title']."</option>";
    }
    $str .= "</select>";
    return $str;
}

根据子类找到上级上上级分类直到顶级为止

function getmenu($cid,&$result=array()){
    //引用数据库连接资源
$row = pdo_get('item',array('id'=>$cid));
    if($row){
        $result[] = $row;
        getmenu($row['pid'],$result);
    }
    //数组顺序倒序
    krsort($result);

    return $result;

}

根据父类查询子类,直到最终子类为止和上面相反

 function get_cid($cid,&$result=array()){
        $row = pdo_getall('item',array('pid'=>$cid));
        if($row){
            foreach($row as $v){
                $result[] = $v;
               get_cid($v['id'],$result);
            }


        }
        return $result;
    }

实际上1,3,4函数比较有用,掌握这几个就掌握了无限分类.

  • 准备工作
阿里云服务器一台,
已安装centos,git,go语言,
nginx端口占用了80,
开通了https占用了443
已备案域名一枚,已解析二级域名 demo.shanliwawa.top

本地客户端win10系统,运行php环境,端口80,服务器Apache+php,注意nginx会出错解析不了.
  • 下载frp
https://github.com/fatedier/frp/releases
国内 http://diannaobos.iok.la:81/frp/
服务器端选择 64位linux  frp_0.20.0_linux_amd64.tar.gz
客户端选windows64位 frp_0.20.0_windows_amd64.zip

服务器端只需要两个文件frps和frps.ini
解压到根目录下 frp文件夹 通过cd进入frp,进入目录执行,注意权限改为777

启动命令 ./frps -c ./frps.ini &
&表示关闭ssh一样运行
ini配置如下,4443是通信端口,客户端也必须相同,8081是服务器端口,因为80被nginx占用了,我们要用服务器端nginx反向代理,代理配置如下


[common]
bind_port = 4443
vhost_http_port = 8081
  • 反向代理配置
map $http_x_forwarded_for $clientRealip {
   "" $remote_addr;
   ~^(?P<firstAddr>[0-9\.]+),?.*$  $firstAddr;
}
server {
       listen 80;
       server_name demo.shanliwawa.top;
       location / {
           proxy_pass http://127.0.0.1:8081;
           proxy_set_header Host $host;
           proxy_set_header X-Real-IP $clientRealip;  # $remote_addr;
           proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
       }
}
  • 客户端配置
解压到D盘frp下,通过cd 进入到frp,只需要frpc和frpc.ini,配置如下,9.9.9.9是我的阿里云IP,4443和上边对应,启动命令:

frpc -c frpc.ini
软件不能关闭,关闭就不能访问了

[common]
server_addr = 9.9.9.9
server_port = 4443
 [web]
type = http
local_ip = 127.0.0.1
local_port = 80
custom_domains =demo.shanliwawa.top

现在就能通过demo.shanliwawa.top访问本地服务器了

织梦操作中,难免不遇到数组,在list标签中,就可以使用数组操作.

[field:array runphp='yes']
    if(@me['litpic']=='/images/defaultpic.gif'){
            @me=    get_imgs(@me['id'],1);
    }else{
            @me=@me['litpic'];
}[/field:array]

这里还应用了一个自定义函数get_imgs().功能是获取图片中第一张.判断了是否有缩率图,有就输出,没有就获取第一张图片.

这里还出现了@me,他是一个代表值,既可以是输出@me=,也可以是传入参数值.
[field:global.autoindex/]
在list这种数剧列表中会输出1,2,3自然数,相当于数组的$k=>$v中$k

顺便说一句,遇到不能在模板中操作的,可以用自定义函数解决,一般常用到数据库操作.明天会讲解在织梦中使用ajax.虽然ajax很简单,但是要在织梦中使用,还是需要一番研究才实现的.

从今天开始,逐渐讲解dedecms建站系统的使用,会有一些开发技巧放出.首先来大概介绍一下使用.

  • 大概目录讲解.后台目录dede会自动登录,模板templates,里面default是默认目录,我们可以建自己的目录作为模板.
  • 模板分三部分,分别是index_开始是封面,也可以作为单页使用;list_是列表页面;article_为文章详细页.后面带_m是移动端模板页面,每个模板都要有对应的移动端模板;
  • 关于菜单制作,需要建立栏目
  • 与表单有关的可以使用自定义表单,然后将生成的代码做成模板即可;
  • 织梦忘记密码 表_admin 密码c3949ba59abbe56e057f对应登录密码123456
    以后会逐步讲解更多织梦技巧

在phpstudy2018中,本想部署5.6php+nginx+虚拟域名tp5.com,可是无论如何都不成功,文件程序目录在c:\www\tp5里面,在这样环境中显示500错误,最后还是没有找到问题,部署微擎和dedecms都没有任何问题.网上有很多修改配置文件的,没有一个可以成功的,我把目录指向c:\www\tp5\public,最终放弃.

只好改成apache试试看看能不能成功,没想到成功了一样是指向c:\www\tp5\public,配置文件要在vhosts.ini里面,全部配置如下

<VirtualHost _default_:80>
DocumentRoot "C:\www"
  <Directory "C:\www">
    Options +Indexes +FollowSymLinks +ExecCGI
    AllowOverride All
    Order allow,deny
    Allow from all
    Require all granted
  </Directory>
</VirtualHost>

<VirtualHost *:80>
    DocumentRoot "C:\www\tp5\public"
    ServerName tp5.com
    ServerAlias 
  <Directory "C:\www\tp5\public">
      Options FollowSymLinks ExecCGI
      AllowOverride All
      Order allow,deny
      Allow from all
     Require all granted
  </Directory>
</VirtualHost>

<VirtualHost *:80>
    DocumentRoot "C:\www\hxcms"
    ServerName hxcms.com
    ServerAlias 
  <Directory "C:\www\hxcms">
      Options FollowSymLinks ExecCGI
      AllowOverride All
      Order allow,deny
      Allow from all
     Require all granted
  </Directory>
</VirtualHost>

<VirtualHost *:80>
    DocumentRoot "C:\www\dedecms"
    ServerName dedecms.com
    ServerAlias 
  <Directory "C:\www\dedecms">
      Options FollowSymLinks ExecCGI
      AllowOverride All
      Order allow,deny
      Allow from all
     Require all granted
  </Directory>
</VirtualHost>

<VirtualHost *:80>
    DocumentRoot "C:\wwwweixin"
    ServerName weixin
    ServerAlias 
  <Directory "C:\wwwweixin">
      Options FollowSymLinks ExecCGI
      AllowOverride All
      Order allow,deny
      Allow from all
     Require all granted
  </Directory>
</VirtualHost>

最后访问没有任何问题.
host文件修改如下

127.0.0.1       localhost
127.0.0.1     tp5.com
127.0.0.1       hxcms.com
127.0.0.1       dedecms.com
127.0.0.1       weixin.com

Excel.php

<?php
//没有命名空间类加载方式 调用类用\
require_once IA_ROOT . '/framework/library/phpexcel/PHPExcel.php';
require_once IA_ROOT . '/framework/library/phpexcel/PHPExcel/IOFactory.php';

class Excel{

   
    private $xls='.xls';//保存文件后缀
     private $xlsx='.xlsx';//保存文件后缀
    private $excelPath;//文件保存的绝对位置
    private $letter=["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P","Q","R","S","T","U","V","W","X","Y","Z"];
    //Excel5和Excel2007
    private $ExcelVersion=['Excel2007','Excel5'];

    private $sheetNum=0;
    //phpExcel实例化对象
    private $phpExcel;
    private $phpWriter;
    private $xlsReader;
    private $phpSheet;

    public function __construct()
    {
        //  实例化PHPExcel类
        $this->phpExcel = new PHPExcel();
       
    }

    /**
     * 创建新的Sheet 支持链式操作
     * @param string $sheet_title
     * @param array  $data       导出数据内容
     * @param array  $excelHeader导出表头
     * @return $this
     * @throws \Exception
     * @throws \PHPExcel_Exception
     */
    public function createSheet($sheet_title='Sheet1',$data=[],$excelHeader=[])
    {
        if ( empty($excelHeader)||!is_array($excelHeader)){
            throw new Exception("Parameter is incorrect");
            return $this;
        }
        $sheet_num = $this->getNewSheetNum();
        $objPHPExcel=$this->phpExcel;
        $objPHPExcel->createSheet($sheet_num);
        //设置当前的sheet
        
        $objPHPExcel->setActiveSheetIndex($sheet_num);
        //设置sheet的name
        $objPHPExcel->getActiveSheet()->setTitle($sheet_title);
        $sheet=$objPHPExcel->getActiveSheet();
       //表头设置
        $excelHeader=array_values($excelHeader);
        foreach($excelHeader as $item=>$value){
            $sheet->setCellValue($this->letter[$item]."1",$value);
        }
       //表内容设置
        foreach($data as $item=>$value ){
            $value=array_values($value);
            foreach($value as $i=>$v)
            //$sheet->setCellValue($this->letter[$i].($item+2),$value[$i]);
            $sheet->setCellValueExplicit($this->letter[$i].($item+2),$value[$i], PHPExcel_Cell_DataType::TYPE_STRING);
        }
        return $this;
    }


    /**
     * 导出下载
     * @return output  
     */ 
    public function downFile($excelName='',$ver='xls')
    {
        ob_start();
        if(empty($excelName)){
            $excelName = 'Excel'.date("Ymdhis");
        }
        try{
            if($ver=='xls'){
              $this->phpWriter = PHPExcel_IOFactory::createWriter($this->phpExcel,$this->ExcelVersion[1]);
              $ext = $this->xls;
            }else{
              $this->phpWriter = PHPExcel_IOFactory::createWriter($this->phpExcel,$this->ExcelVersion[0]);
              $ext = $this->xlsx;
            }   
        }catch(Exception $e){
            throw new Exception("Export failed");
        }
        header('Content-Type: application/vnd.ms-excel; charset=utf-8');
        header("Content-Disposition: attachment;filename=".$excelName.$ext);
        header('Cache-Control: max-age=0');
        $this->phpWriter->save('php://output');  
        ob_end_flush();
        die();
    }
    /**
     * 导出保存服务器上
     * @param  String  $path 保存路径
     * @param  boolean $activate 自定义保存路径需要将此处设置为true
     * @return Object  
     */ 
    public function saveFile($excelName='',$filepath='',$ver='xls')
    {
        
        if (empty($filepath)) {
            $filepath  =  IA_ROOT.'/data/Excel/';
        }
        if(empty($excelName)){
            $excelName = 'Excel'.date("Ymdhis");
        }
        if(!$this->checkPath($filepath)){
            throw new Exception("The current directory is not writable");
        } else{
            try{
                 if($ver=='xls'){
              $this->phpWriter = PHPExcel_IOFactory::createWriter($this->phpExcel,$this->ExcelVersion[1]);
              $ext = $this->xls;
            }else{
              $this->phpWriter = PHPExcel_IOFactory::createWriter($this->phpExcel,$this->ExcelVersion[0]);
              $ext = $this->xlsx;
            }  
            }catch(Exception $e){
                throw new Exception("Export failed");
            }
          
            $this->excelPath=$filepath.$excelName.$ext;
            $this->phpWriter->save($this->excelPath); 
            return $this;
        }

    }
    /**
     * 导入基本设置
     * @param  String  $path 保存路径
     * @param  boolean $activate 自定义保存路径需要将此处设置为true
     * @return Object  
     * @throws Exception
     * @throws \PHPExcel_Exception
     */ 
    public function loadExcel($filepath)
    {
      if(!is_file($filepath)){
        throw new Exception("File does not exist");
      }
       try{$type = strtolower( pathinfo($filepath, PATHINFO_EXTENSION) );
            if($type=='xlsx'){
                $xlsReader =  PHPExcel_IOFactory::createReader($this->ExcelVersion[0]);
                $xlsReader->setReadDataOnly(true); 
                $xlsReader->setLoadSheetsOnly(true);
                $this->xlsReader=$xlsReader->load($filepath);
            }elseif('xls'==$type){
                $xlsReader =  PHPExcel_IOFactory::createReader($this->ExcelVersion[1]);
                $xlsReader->setReadDataOnly(true); 
                $xlsReader->setLoadSheetsOnly(true);
                $this->xlsReader=$xlsReader->load($filepath);
            }elseif('csv'==$type){
              $handle = fopen($filepath, 'r');
        $dataArray = array();
        $row = 0;
        while ($data = fgetcsv($handle)) {
            $num = count($data);

            for ($i = 0; $i < $num; $i++) {
                $dataArray[$row][$i] = mb_convert_encoding($data[$i], "utf-8", 'GBK');
            }
            $row++;

        }

        $this->xlsReader= $dataArray;
            }
       }catch(Exception $e){
            throw new Exception("Reading failed");
       }
      return $this->xlsReader;
    }
    /**
     * 获取新的Sheet编号
     * @return int
     */
    protected function getNewSheetNum(){
        $sheet_num=$this->sheetNum;
        $this->sheetNum=$sheet_num+1;
        return $sheet_num;
    }

    /**
     * 检查目录是否可写
     * @param  string   $path    目录
     * @return boolean
     */
    protected function checkPath($path)
    {
        if (is_dir($path)) {
            return true;
        }
        if (mkdir($path, 0755, true)) {
            return true;
        } else {
            return false;
        }
    }
    /**
     * 返回数组的维度
     * @param  Array   $arr 任意数组
     * @return number  数组维度
     */
    protected function array_depth($arr)
    {
        if(!is_array($arr)) return 0;
        $max_depth = 0;
        foreach($arr as $item1)
        {
            $t1 = $this->array_depth($item1);
            if( $t1 > $max_depth) $max_depth = $t1;
        }
        return $max_depth + 1;
    }
}

包含方法有导入,导出,导出模板,支持导入xls,xlsx,csv,导出支持xls,xlsx,使用非常简单

$csv = new Excel();

foreach($rs as $k=>$v){
$data[] = ['用户名'=>$v['username'],'密码'=>$v['password']];
}
$csv = $csv->createSheet('导出表',[],['用户名','密码'])->downFile('文件名','xls');//下载 saveFile('文件名','./','xls')保存到服务器

$csv->loadExcel($_SERVER['DOCUMENT_ROOT'].'/1.xls')->getSheet(0)->toArray();//可读xls,xlsx成数组

$qq = $csv->loadExcel($_SERVER['DOCUMENT_ROOT'].'/1.csv');//读取csv成数组

需要说明 如果导入的数组,数据有空格去除使用下面函数即可

//去除数组中值两端空格
function TrimArray($Input){
    if (!is_array($Input))
        return preg_replace("/(\s|\&nbsp\;| |\xc2\xa0)/","",$Input);

    return array_map('TrimArray', $Input);
}

平常建立网站都希望,www.x.com与x.com是一个网站,如何做到呢?
创建网站时候站点域名一定要带上www.x.com这样去创建网站.
然后我们建立一个.htaccess文件,内容如下,编码utf-8

<IfModule mod_rewrite.c>
RewriteEngine onRewriteCond %{http_host} ^yoby123.cn [NC]
RewriteRule ^(.*)$ https://www.yoby123.cn/$1 [L,R=301]
</IfModule>

里面网站自己改吧
然后把这个文件上传到/www/web/www_yoby123_cn/public_html这样一个目录下就可以,
以后就会自动跳转到带www

我收集制作的 (https://packagist.org/packages/logoove/)

常用函数工具类

composer require logoove/fn dev-master
phpexcel导入导出类

composer require logoove/phpexcel dev-master
pdo操作封装类,类名同微擎1.7版本

composer require logoove/pdo dev-master
oauth2

composer require logoove/oauth2 dev-master
拼音类

composer require logoove/pinyin dev-master
验证码类

composer require logoove/verify dev-master
smarty模板

composer require logoove/smarty dev-master
smtp发送邮件20kb大小类无任何依赖

composer require logoove/smtp dev-master

如果随着php命名空间使用,采用composer会非常方便,不用些重复代码,每个项目只需要通过composer就能重复利用库代码.

1 . 在github上注册一个项目,比如我的,注册为名称fn,项目版权选择的是MIT,然后更新到本地电脑,方便编写库.在本地fn目录下创建src目录,并新建文件Fn.php在src目录下.
2 . 通过cmd命令切换到fn目录下,输入composer init,来创建composer.json文件,注意编码要改成utf-8,生成的好像不是,当然也可以找一个复制过来修改.
composer.json更容是

{
    "name": "logoove/fn",
    "description": "这是一个函数组成的类库,包含大量自定义函数,后续都会从这里更新,以后不用重复定义常见方法",
        "type": "library",
          "license": "MIT",    
    "authors": [{
        "name": "yoby",
        "email": "logove@qq.com"
    }],
  "minimum-stability": "dev",
    "require": {},
    "autoload": {
        "psr-4": {
            "logoove\\fn\\": "src"
        }
    }
}

具体参数意思是name为项目名字,通过/隔开,logoove是我github账号名,fn是项目名字
description是描述,type不用改,authors自己改成你自己的,autoload是自动加载规则,改成你自己路径
完成以后就能够编写Fn.php自己了.
我们可以使用命名空间,命名空间最好统一采用 用户名\项目名
文件名要和你定义的类名相同.
没有使用命名空间的类的加载采用 require_once "PHPExcel.php";这种方式即可
这样我们就可以把以前一些项目改写成符合自动加载类库.

3 . 编写好以后记得提交到到github,然后去 (https://packagist.org) 注册一个帐号,最好也采用github帐号登录.你的每一个库在github上都有独立项目名.最后提交github地址到packagist.org即可.我们以后修改项目在github,那么composer这边如何更新呢,那就是设置同步.
先切换到profile,可以看到底部有个Your API Token,复制下来,然后去github项目的settings->Integrations & services->add server->Packagist,这时候有user,token,domain三个要填写的,我的就是 logoove,刚刚复制的Token,域名就是https://packagist.org/,这样就能自动同步了.
4 . 最后你的库就完成了,任何php项目都能使用了,一个命令搞定,免去每次复制粘贴库代码,你也能分享给更多用户使用

windows安装composer,运行 Composer 需要 PHP 5.3.2+ 以上版本

  • 下载(https://getcomposer.org/Composer-Setup.exe)
  • 安装需要选择php.exe路径,比如phpstudy里面包含很多php,所以可以选择一个合适php版本
  • 安装完成后,需要打开cmd命令,输入composer可以查看安装的信息
  • 更改为国内镜像
    composer config -g repo.packagist composer https://packagist.phpcomposer.com
  • 使用,在cmd下,用cd命令进入到项目目录,执行composer.json文件,命令是
composer install

如果有composer.lock文件需要删除,这样就能执行了

说下我的php是phpstudy,版本php用的5.6nts.

  • 找到phpini文件打开后最后一行去掉分号.phpstudy在C盘下,改成如下,注意你自己安装目录
zend_extension="C:\server\php\PHPTutorial\php\php-5.6.27-nts\ext\php_xdebug.dll"
xdebug.remote_enable = on
xdebug.profiler_enable = off
xdebug.profiler_enable_trigger = off
xdebug.profiler_output_name = cachegrind.out.%t.%p
xdebug.profiler_output_dir ="C:\server\php\tmp"
xdebug.show_local_vars=0
xdebug.remote_handler = dbgp
;设置xdebug的端口为9001
xdebug.remote_port = 9001
;设置idekey
xdebug.idekey="PHPSTORM"
  • 在文件-设置-语言和框架-PHP找到如图,添加php.exe
    图片

请输入图片描述请输入图片描述

请输入图片描述

说到php开发神器phpstorm,下载汉化版https://pan.baidu.com/s/1nHghHl0_D4QFcKZcIA8pTg,可以说非常好用,如果内存4G机器用起来非常卡,怎么来优化呢?

  • 安装过程,很简单,最后把汉化文件复制到安装文件夹的lib目录,打开就是中文版,官方是没有中文版的,安装完成后,网站搜索激活网站就行了.
  • 需要注意设置工作目录尽量文件少,工作目录,否则打开软件索引时候占用全部cpu,卡的不行
  • 还有设置里面关闭不需要的插件,减少内存的大小.
  • 打开滨 目录 PhpStorm64.exe,注意需要安装64位JDK,不要用生成的快捷方式.

经过设置只占用内存不到400MB,不改的话有1G,所以优化还是非常重要的,后面介绍设置phpstorm xdebug断点调试设置.

遇到 占用cpu到100%,很烦,
关闭它有两种方法,一种是关闭启动进程扫描。另一种是关闭windows defende。

  • 鼠标移动到电脑桌面左下角,右键点一下开始,点里面的“运行”,或着win键+R键打开“运行”。
  • 运行里输入:gpedit.msc
  • 依次打开:管理模板----windows组件----windows Defender。
  • 找到windows Defender下的“实时保护”。然后鼠标双击右侧的“不论何时启用实时保护,都会启用进程扫描.
  • 在弹出的设置页面选已禁用。保存就行了。
  • 如果还不能解决我们可以用第二种方法就是禁用windows Defender。
    我们用上面的方法依次打开:管理模板----windows组件--找到-windows Defender,鼠标点一下windows Defender。在右侧找到”关闭windows Defender"并用鼠标双击它
  • 在打开的设置页面,选:已启用。确定之后就会禁用windows Defender。

表单验证jquery插件Validform是比较好用的,只需要加载css和jquery插件就能很方便使用.

<form class="demoform">
<input type="text" value="" name="name" datatype="s5-16" errormsg="昵称至少5个字符,最多16个字符!" />
</form>

初始化$(".demoform").Validform();一句就可以了

内置基本的datatype类型有: | 6-16 | n | n6-16 | s | s6-18 | p | m | e | url
*:检测是否有输入,可以输入任何字符,不留空即可通过验证;
*6-16:检测是否为6到16位任意字符;
n:数字类型;
n6-16:6到16位数字;
s:字符串类型;
s6-18:6到18位字符串;
p:验证是否为邮政编码;
m:手机号码格式;
e:email格式;
url:验证字符串是否为网址。
自定义datatype的名称,可以由字母、数字、下划线、中划线和*号组成。
形如"6-16"的datatype,Validform会自动扩展,可以指定任意的数值范围。如内置基本类型有"6-16",那么你绑定datatype="*4-12"就表示4到12位任意字符。如果你自定义了一个datatype="zh2-4",表示2到4位中文字符,那么datatype="zh2-6"就表示2到6位中文字符。
5.2版本之后,datatype支持规则累加或单选。用","分隔表示规则累加;用"|"分隔表示规则多选一,即只要符合其中一个规则就可以通过验证,绑定的规则会依次验证,只要验证通过,后面的规则就会忽略不再比较。如绑定datatype="m|e",表示既可以填写手机号码,也能填写邮箱地址,如果知道填入的是手机号码,那么就不会再检测他是不是邮箱地址;datatype="zh,s2-4",表示要符合自定义类型"zh",也要符合规则"s2-4"。
注:
5.2.1版本之后,datatype支持:
直接绑定正则:如可用这样写datatype="/w{3,6}/i",要求是3到6位的字母,不区分大小写;
支持简单的逻辑运算:如datatype="m | e, *4-18 | /w{3,6}/i | /^validform.rjboy.cn$/",
这个表达式的意思是:可以是手机号码;或者是邮箱地址,但字符长度必须在4到18位;或者是3到6位的字母,不区分大小写;或者输入validform.rjboy.cn,区分大小写。这里","分隔相当于逻辑运算里的"&&"; "|"分隔相当于逻辑运算里的"||";不支持括号运算。
nullmsg
当表单元素值为空时的提示信息,不绑定,默认提示"请填入信息!"。
如:nullmsg="请填写用户名!"
5.3版开始,对于没有绑定nullmsg的对象,会自动查找class为Validform_label下的文字作为提示文字:
如这样的html结构:
<span class="Validform_label">*用户名:</span><input type="text" val="" datatype="s" />
当这个文本框里没有输入时的出错信息就会是:"请输入用户名!"
这里Validform_label跟input之间的位置关系,不一定是要同级关系,同级里没有找到的话,它还会在同级的子级、父级的同级、父级的同级的子级里查找。
sucmsg 5.3+
当表单元素通过验证时的提示信息,不绑定,默认提示"通过信息验证!"。
如:sucmsg="用户名还未被使用,可以注册!"
5.3版开始,也可以在实时验证返回的json数据里返回成功的提示文字,请查看附加属性ajaxurl的介绍。
errormsg
输入内容不能通过验证时的提示信息,默认提示"请输入正确信息!"。
如:errormsg="用户名必须是2到4位中文字符!"
5.3版开始,Validform可以根据你绑定的datatype智能的输出相应出错信息,具体介绍请查看tipmsg
ignore
绑定了ignore="ignore"的表单元素,在有输入时,会验证所填数据是否符合datatype所指定数据类型,
没有填写内容时则会忽略对它的验证;
recheck
表单里面经常需要检查两次密码输入是否一致,recheck就是用来指定需要比较的另外一个表单元素。
如:recheck="password1",那么它就会拿当前元素的值跟该表单下,name为"password1"的元素比较。
tip
表单里经常有些文本框需要默认就显示一个灰色的提示文字,当获得焦点时提示文字消失,失去焦点时提示文字显示。tip属性就是用来实现这个效果。它通常和altercss搭配使用。
如<input type="text" value="默认提示文字" class="gray intxt" tip="默认提示文字" altercss="gray" />
altercss
它需要和tip属性配合使用,altercss指定的样式名,会在文本框获得焦点时被删除,没有输入内容而失去焦点时重新加上。
ajaxurl
指定ajax实时验证的后台文件的地址。
后台页面如valid.php文件中可以用 $_POST["param"] 接收到值,Ajax中会POST过来变量param和name。param是文本框的值,name是文本框的name属性。
5.2版本开始,可以在ajaxurl指定的url后绑定参数,如:ajaxurl="valid.php?myparam1=value1&myparam2=value2"; 5.3.1开始,地址后面附带的参数内部不再做另外解析,仍附带在地址后面,所以需要用GET方式去获取地址后面带的参数。
5.3之前的版本中,该文件输出的字符会作为错误信息显示在页面上,如果验证通过需输出小写字母"y"。
在5.3版中,实时验证的返回数据做了调整,须是含有status值的json数据!跟callback里的ajax返回数据格式统一,建议不再返回字符串"y"或"n"。目前这两种格式的数据都兼容。
注:
如果ajax校验通过,会在该元素上绑定validform_valid值为true。可以通过设置该值来控制验证能不能通过,如验证码的验证,第一次验证通过后,不小心右点击了下验证码图片,验证码换了,但是仍然指示这个对象已经通过了验证,这时可以手动调整该值:$("#name")[0].validform_valid="false"。
怎样设置ajax的参数,具体可以查看Validform对象的config方法。

下载地址 http://validform.rjboy.cn

QQ音乐非常不错,2018年qq音乐修改了网站搜索,以前的接口已经不能用了,笔者在此做了一个新的接口,可以搜索到音乐的真正播放地址,描述,以及相册封面等信息,可以用来做音乐相关应用.接口代码如下,只需要歌曲关键字即可搜索10条数据.

function somusic($keyword="东风破") {//搜索QQ音乐
        $time = time()*1000;
$url = "http://i.y.qq.com/s.music/fcgi-bin/search_for_qq_cp?g_tk=5381&uin=0&format=jsonp&inCharset=utf-8&outCharset=utf-8&notice=0&platform=h5&needNewCode=1&w=".urlencode($keyword)."&zhidaqu=1&catZhida=1&t=0&flag=1&ie=utf-8&sem=1&aggr=0&perpage=20&n=10&p=1&remoteplace=txt.mqq.all&_=".$time."&jsonpCallback=jsonp4";
$ch=curl_init($url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER,1);
$data  =  curl_exec($ch);
curl_close($ch);

$rs=substr($data,7,strlen($data)-8);
$list = json_decode($rs,1);

if(count($list['data']['song']['list'])>0){
$arr = array();
foreach($list['data']['song']['list']  as  $v){
$arr[] = array(
'id'=>$v["songid"],
"songname"=>$v["songname"],
"desc"=>$v["singer"][0]['name']."---".$v["songname"],
'musicurl'=>"http://ws.stream.qqmusic.qq.com/C100".$v['songmid'].".m4a?fromtag=38",
'pic'=>"http://y.gtimg.cn/music/photo_new/T002R150x150M000".$v['albummid'].".jpg?max_age=2592000"
);

}
}else    {
$arr = array();
}


if(count($arr)>0){

$str = $arr;

}else{
$str = "未找到相关音乐";

}
return $str;
    }

请不要做违法应用,支持正版音乐