解决PhpStorm2018.1之后不能更改PHP语法版本的问题

根据在达内太原PHP网站上找到的,在JetBrains的官方论坛中有原因:composer.json中设置了PHP的版本。 解决办法主要有以下几种:
  1. 在composer.json中更改语言版本,例如”php”: “>=5.4.0″改成”php”: “>=7.1.0” ;
  2. 在”Settings/Preferences | Languages & Frameworks | PHP | Composer”中取消自动与composer同步(Synchronize IDE Settings with composer.json);
  3. 删除composer.json文件。不推荐此用法,会导致第三方依赖库不能下载,失去自动补全功能;
  4. 使用旧版的PhpStorm。论坛反馈和本人亲身体验,旧版不会读取composer.json文件锁定语言版本,升级到2018.1版本中才会无法更改语法版本。
  5. 也可以对左边目录树里的额外库(External Libraries)目录右键,选择Configure PHP Include Path,但是这么做的缺点是每次重启IDE之后都得配置一遍
PS: File菜单下以前有个Default Setting的设置,现在变成了Settings for New Projects,在这里无法配置上述Composer关系... 点开看看

composer更新包时报错”has uncommitted changes”

composer
今天在自己的一个项目中更新另一个自己的包时报错了,“has uncommitted changes”,导致无法更新。 本来猜的是另一个包的原因,百度上什么都没有,后来去谷歌了下,在StackOverflow上发现有个大佬解决了这个问题: 这是原文,总结下就是
    1. 在项目根目录下composer status -v 查看哪个文件被修改了,正常的话应该是No local changes,如果有问题的话,就会显示文件的修改记录,比如说
      You have changes in the following dependencies:
      /Users/adrienbrault/Developer/SymfonyApp/vendor/symfony/symfony:
          M src/Symfony/Component/HttpKernel/Kernel.php
    2. 根据上述提示,去cd到相应的目录下
    3. git checkout .
    4. 回到项目根目录下composer status -v查看现在的版本差异,没问题的话就可以开心的composer install composer update了~
很简单的步骤,但是百度上真的查不到,只能另寻出路。 翻墙是个双刃剑,对没有成熟的三观的人,不异于彼岸之花;可对于做技术的人来说,却像沙漠中混着泥沙的泉水。... 点开看看

nikic/fast-route中文文档

之前在跟随@岁寒大佬的《利用 Composer 一步一步构建自己的 PHP 框架》 搭建了自己的  DoyleafPHP,路由使用的是GayHub上route关键词PHP语言下MostStars第一的nikic/fast-route,上一张现在的图  

安装方式

通过composer安装: composer require nikic/fast-route 需要PHP 5.4及更高版本.

使用方法

快速构造

<?php

// 引入composer自动加载文件
require '/path/to/vendor/autoload.php';

// 声明路由规则*
$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
    $r->addRoute('GET', '/users', 'get_all_users_handler');
    // {id} must be a number (\d+)
    $r->addRoute('GET', '/user/{id:\d+}', 'get_user_handler');
    // The /{title} suffix is optional
    $r->addRoute('GET', '/articles/{id:\d+}[/{title}]', 'get_article_handler');
});

// 获取http请求方式和资源URI
$httpMethod = $_SERVER['REQUEST_METHOD'];
$uri = $_SERVER['REQUEST_URI'];

// 将url中的get传参方式(?foo=bar)剥离并对URI进行解析
if (false !== $pos = strpos($uri, '?')) {
    $uri = substr($uri, 0, $pos);
}
$uri = rawurldecode($uri);

$routeInfo = $dispatcher->dispatch($httpMethod, $uri);

// 根据调度器进行匹配
switch ($routeInfo[0]) {

    // 使用未定义路由格式
    case FastRoute\Dispatcher::NOT_FOUND:
        // ... 404 Not Found
        break;

    // 请求的HTTP⽅法与配置的不符合
    case FastRoute\Dispatcher::METHOD_NOT_ALLOWED:
        $allowedMethods = $routeInfo[1];
        // ... 405 Method Not Allowed
        break;

    // 调用$handler和$vars*
    case FastRoute\Dispatcher::FOUND:
        $handler = $routeInfo[1];
        $vars = $routeInfo[2];
        // ... call $handler with $vars
        break;
}

定义路由

通过调用 FastRoute\simpleDispatcher() 函数来定义路由,参数为可调用的FastRoute\RouteCollector实例。   通过在收集器实例上调用addRoute()来添加路由:
$r->addRoute($method, $routePattern, $handler);

$method参数是该条路由匹配的一个大写的HTTP方法字符串。可以使用数组指定多个有效方法:
// 分两条调用
$r->addRoute('GET', '/test', 'handler');
$r->addRoute('POST', '/test', 'handler');

// 也可以一次性调用
$r->addRoute(['GET', 'POST'], '/test', 'handler');

$routePattern参数默认使用以下语法:{foo} 指定的名称为foo的占位符,与正则表达式[^/]+匹配。若要调整占位符正则匹配的模式,可以通过编写{bar:[0-9]+}来指定自定义模式。举个例子:.
// 允许匹配/user/42, 不匹配/user/xyz
$r->addRoute('GET', '/user/{id:\d+}', 'handler');

// 允许匹配/user/foobar,不匹配/user/foo/bar
$r->addRoute('GET', '/user/{name}', 'handler');

// 允许匹配/user/foo/bar
$r->addRoute('GET', '/user/{name:.+}', 'handler');

路由占位符的自定义模式不能使用捕获组。例如 {lang:(en|de)} 就不是一个有效的占位符,因为() 是一个捕获组。 但是您可以使用 {lang:en|de}{lang:(?:en|de)}。 (这里的捕获组我理解的就是可选项,只能是这二者之一的意思) 此外,可以使用[...]来表示可选路由,因此 /foo[bar]既能匹配 /foo,也能匹配/foobar 可选部件仅可以出现在末尾位置,而不能出现在路径中间。
// 使用可选语法的路由
$r->addRoute('GET', '/user/{id:\d+}[/{name}]', 'handler');
// 可以相当于下列两条同时存在
$r->addRoute('GET', '/user/{id:\d+}', 'handler');
$r->addRoute('GET', '/user/{id:\d+}/{name}', 'handler');

// 多个嵌套可选部件也是可用的
$r->addRoute('GET', '/user[/{id:\d+}[/{name}]]', 'handler');

// 这条路由就是错误的,因为可选部分必须出现在末尾
$r->addRoute('GET', '/user[/{id:\d+}]/{name}', 'handler');
$handler 参数不一定非要是回调函数,它可以是一个控制器的类名,或者其他任何你想要与路由相关联的类型的数据。FastRoute只告诉你你的URI对应哪个处理程序,你如何解释它取决于你。

常用请求的快捷写法

对于 GET, POST, PUT, PATCH, DELETEHEAD 方式的请求,我们提供了对应的快捷写法。举个例子:
$r->get('/get-route', 'get_handler');
$r->post('/post-route', 'post_handler');
这两条路由就相当于:
$r->addRoute('GET', '/get-route', 'get_handler');
$r->addRoute('POST', '/post-route', 'post_handler');

路由组

另外,您可以使用路由组来指定路由。 组内定义的所有路由都会拥有一个通用前缀。 举个例子,你可以像这样定义你的多条路由:
$r->addGroup('/admin', function (RouteCollector $r) {
    $r->addRoute('GET', '/do-something', 'handler');
    $r->addRoute('GET', '/do-another-thing', 'handler');
    $r->addRoute('GET', '/do-something-else', 'handler');
});
我们得到的结果就相当于:
$r->addRoute('GET', '/admin/do-something', 'handler');
$r->addRoute('GET', '/admin/do-another-thing', 'handler');
$r->addRoute('GET', '/admin/do-something-else', 'handler');
也可以对组进行嵌套,所有被嵌套的组的前缀都会被合并到一起。

缓存

我们支持无缝缓存,所以simpleDispatcher可以通过回调来定义路由。 使用cachedDispatcher来替换simpleDispatcher,您可以将生成的路由数据进行缓存,以从缓存数据中构建调度程序:
<?php

$dispatcher = FastRoute\cachedDispatcher(function(FastRoute\RouteCollector $r) {
    $r->addRoute('GET', '/user/{name}/{id:[0-9]+}', 'handler0');
    $r->addRoute('GET', '/user/{id:[0-9]+}', 'handler1');
    $r->addRoute('GET', '/user/{name}', 'handler2');
}, [
    'cacheFile' => __DIR__ . '/route.cache', /* required */
    'cacheDisabled' => IS_DEBUG_ENABLED,     /* optional, enabled by default */
]);
方法的第二部分是一个可选数组,可用于指定缓存文件的位置等。

对URI进行调度

URI通过已生成的dispatcher中的dispatch() 方法来调用。这个方法可以用来接收HTTP参数和URI。这个库不会绑定到PHP Web SAPI上,所以您可以自行获取这两部分信息(并适当地标准化)。 dispatch()方法返回一个数组,这个数组的第一个元素包含一个状态码。这个状态码只能是Dispatcher::NOT_FOUND, Dispatcher::METHOD_NOT_ALLOWEDDispatcher::FOUND对于Method Not Allowed状态,返回数组的第二个元素是一个列表,这个列表包含了本URI可用的HTTP请求方式。 像这样:
[FastRoute\Dispatcher::METHOD_NOT_ALLOWED, ['GET', 'POST']]
说明:HTTP规范要求405 Method Not Allowed响应包含“Allow:”头,用以详细说明所请求资源的可用方法。 使用FastRoute的应用程序在返回405响应时,应使用数组的第二个元素添加此标头。
对于得到的这个状态码(即405),第二个数组元素是与路由关联的句柄,第三个数组元素是一个键值对应的占位符的字典。 就像这样:
/* 路由拒绝了/user/nikic/42的GET请求 */

[FastRoute\Dispatcher::FOUND, 'handler0', ['name' => 'nikic', 'id' => '42']]

重写路由解析器和调度器(写到这发现网上有中文文档是一种什么体验,CNNN,MMP)

这个库使用三个组件,一个路由解析器,一个数据生成器,一个调度器。这个三个组件由以下接口实现:
<?php

namespace FastRoute;

interface RouteParser {
    public function parse($route);
}

interface DataGenerator {
    public function addRoute($httpMethod, $routeData, $handler);
    public function getData();
}

interface Dispatcher {
    const NOT_FOUND = 0, FOUND = 1, METHOD_NOT_ALLOWED = 2;

    public function dispatch($httpMethod, $uri);
}
路由解析器获取路由模式字符串并将其转换为路由信息数组,其中每个路线信息又是它的部分数组。
/* 本路由/user/{id:\d+}[/{name}]被转化为下述数组: */
[
    [
        '/user/',
        ['id', '\d+'],
    ],
    [
        '/user/',
        ['id', '\d+'],
        '/',
        ['name', '[^/]+'],
    ],
]
然后可以将该数组传递给数据生成器的 addRoute() 方法,在添加了所有路由之后,调用生成器的 getData(),它将返回调度器所需的所有路由数据。 调度程序通过构造函数接受路由数据,并提供 dispatch()方法。 路由解析器可以被单独覆盖,然而数据生成器和调度器应该总是一起修改,因为前者的输出与后者的输入紧密耦合。 当使用 simpleDispatcher / cachedDispatcher 时,可以通过传入额外的参数,进行覆盖
<?php

$dispatcher = FastRoute\simpleDispatcher(function(FastRoute\RouteCollector $r) {
    /* ... */
}, [
    'routeParser' => 'FastRoute\\RouteParser\\Std',
    'dataGenerator' => 'FastRoute\\DataGenerator\\GroupCountBased',
    'dispatcher' => 'FastRoute\\Dispatcher\\GroupCountBased',
]);
上面给出了默认的设置,通过把 GroupCountBased 替换成 GroupPosBased 可以使用完全不同的调度策略

关于HEAD请求的说明

HTTP 规范要求服务器 同时支持 GET 和 HEAD 方法
GET和HEAD方法必须得到所有通用服务器的支持
为避免强制用户为每个资源手动注册 HEAD 路由,将使用一个匹配的 GET 路由响应请求。PHP web SAPI 透明地从 HEAD 响应中移除实体主体,所以这种行为对绝大多数用户没有影响。 但是,在 Web SAPI 环境外部使用 FastRoute ,绝不能发送响应 HEAD 请求而生成的实体主体,如果你是非 SAPI 用户,这是你的责任;在这种情况下,FastRoute 无权限制你破坏 HTTP 。 最后,请注意,应用程序可以始终为给定资源指定其自己的 HEAD 方法路由以完全绕过此行为。  
... 点开看看

转自菜鸟教程——适用于PHP初学者的学习线路和建议

先来看下PHP初学者的学习线路:

  • (1) 熟悉HTML/CSS/JS等网页基本元素,完成阶段可自行制作简单的网页,对元素属性相对熟悉。
  • (2) 理解动态语言的概念和运做机制,熟悉基本的PHP语法。
  • (3) 学习如何将PHP与HTML结合起来,完成简单的动态页面。
  • (4) 接触学习MySQL,开始设计数据库。
  • (5) 不断巩固PHP语法,熟悉大部分的PHP常用函数,理解面向对象编程,MySQL优化,以及一些模板和框架。
  • (6) 最终完成一个功能齐全的动态站点。

  • 新手不要看到上面的概括就以为PHP学习是很简单的,编程是需要你认真的思考和不断的实践。下面具体解释一下PHP的学习线路。首先,任何网站都是由网页组成的,也就是说想完成一个网站,必须先学会做网页,掌握静态网页的制作技术是学习开发网站的先决条件。因此我们要学习HTML,为今后制作网站打下基础。学习HTML应该边学边做,HTML中的任何元素都要亲自实践,只有明白了什么元素会起到什么效果之后,才能深刻记忆,一味的看书是不行的。
  • 假设你已经可以完成一个静态页面了,那么就该开始了解动态语言,刚一接触动态语言,可能很多人都会有很多不解,代码不是作为直接输出的,而是要经过处理的,HTML是经过HTML解析器,而PHP也要通过PHP解析器,跟学习HTML一样的道理,想让任何的解析器工作,就必须使用它专用的语法结构。
  • 学习PHP,你应该感到幸运,因为如果你学过其他语言,你就会发现PHP还是相对简单的,这一阶段,你要搞清楚HTML和PHP的概念,你现在完全可以让PHP给你算算一加一等于几,然后在浏览器输出。不要觉得幼稚,这虽然是很小的一段代码,但是对于你的编程之路,可是迈出了一大步。不过现在,你还是一个菜鸟。
  • 接下来就要学习数据库了,MySQL可以说是PHP的黄金搭档,我们要征服这个数据库,在你理解了数据库的概念之后,就要尝试通过PHP来连接数据库,进而会用PHP成功的插入,删除和更新数据。
  • 这个时候,你可能会处于这种状态:你会HTML吗?会,我能编好几个表格排板的网页呢!你会PHP吗?会,我会把一加一的运算写在函数里,然后调用!你会MySQL吗?会,我可以把数据库里的数据插入删除啦!
  • 那接下来该做什么呢?尝试着做个小的留言本吧,这同样是新手面临的一道关卡。花了一段时间,你终于学会把表单的数据插入数据库,然后显示出来了,应该说一个程序的雏形已经诞生了。但是,你可能会看人家这个编论坛,那个开发CMS,我什么时候可以写一个呢?不要急,再巩固一下知识,熟悉了PHP和MySQL开发的要领后,再回头看你写的那个留言本,你也许会怀疑那真的是你写的吗?这个时候,你可以完善一下你写的留言本。留言本应该加入注册以及分页的功能,可以的话,UI也可以加强。
  • 这就算学会了吗?NO,NO,NO,还早呢,你到现在还没碰过OOP呢吧?那模板和框架呢?还要继续学习呀!PHP框架提供了一个用以构建web应用的基本框架,从而简化了用PHP编写web应用程序的流程。可以节省开发时间、有助于建立更稳定的应用。所以说,PHP框架是一个可以用来节省时间并强化自己代码的工具。当你第一次选择PHP框架时,建议多尝试几个,每个框架都有自己的长处和短处,例如Zend框架由于多样的功能、并且有一个广泛的支持系统,流行了很长时间。而CakePHP是一个晚于Zend的PHP框架,相应的支持系统也比较少,但是更为方便和易于使用。
  • 了解了面向对象和框架后,你应该接触一下XML了,总而言之,你绝对不会发现你全部都学会了,学无止境!学东西,永远不要妄想有速成这一说,技巧再多,但是缺少努力,那也是白搭。有一点可以保证,就是你学会了PHP,那么再学其它语言,肯定速成,反过来也一样,如果你之前学过其它的语言,那么学PHP肯定快。
  • 多借鉴别人成功的代码,绝对是有益无害,所以要多看那些经过千锤百炼凝出来的经典代码,是进步的最好方法。另外,要强调的是,学习一项技术过程中可能会遇到困难,可能会迷茫,你也许学了一半的PHP,又开始打C#的主意,或者有人说Java很好,这个时候你绝对不能动摇,要坚持到底,彻底学会。祝你顺利学成PHP,开发自己想要的网站。
... 点开看看

有一种图片形式是“data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEBAQ…==”

昨天用到一个前端裁剪插件,在jq22上花了六个币下的,裁剪之后的数据是: “data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAAAQABAAD/2wBDAAEBAQEBAQEBAQ…==”这种形式的。 看起来是个二进制流的图片,毕竟data:image/jpeg了,但是直接把这一串传给后端写入”*.jpg”的文件之后无法打开,说明这串数据并不是二进制流的图片,但是转了base64之后还是不能用,那怎么处理呢? 后来在网上搜base64转图片到了一片博客,文中整理了一个函数用来处理这块,现在稍作修改,粘在这里留个备份,以便将来查阅
/**
 * [将Base64图片转换为本地图片并保存]
 * @E-mial wuliqiang_aa@163.com
 * @TIME   2017-04-07
 * @WEB    http://blog.iinu.com.cn
 * @param  [Base64] $base64_image_content [要保存的Base64]
 * @param  [目录] $path [要保存的路径]
 * @return bool|string
 */
private function base64_image_content($base64_image_content,$path){
    //匹配出图片的格式
    if (preg_match('/^(data:\s*image\/(\w+);base64,)/', $base64_image_content, $result)){
        $type = $result[2];
        $new_file = $path;
        if(!file_exists($new_file)){
            //检查是否有该文件夹,如果没有就创建,并给予最高权限
            mkdir($new_file, 0700);
        }
        $new_file = $new_file.uniqid().".{$type}";
        if (file_put_contents($new_file, base64_decode(str_replace($result[1], '', $base64_image_content)))){
            return '/'.$new_file;
        }else{
            return false;
        }
    }else{
        return false;
    }
}
... 点开看看