laravel guzzle 使用

安装:
composer.json 添加  "guzzlehttp/guzzle": "~6.0",
然后执行:
composer update guzzlehttp/guzzle
完成安装
使用:
首先 use:
use GuzzleHttp\Client;
使用举例:
$client = new Client();
try {
    $response = $client->request('PUT',$url,[
        'body' => json_encode(['foo' => 'bar'])
    ]
    );
    Log::info('返回');
    $statusCode = $response->getStatusCode();
    $rsp = $response->getBody()->getContents();
    //$arrRes = json_decode($rsp, true);
    Log::info($statusCode);
    Log::info($rsp);
} catch (\Exception $e) {
    echo 'error:  ';
    echo $e->getMessage();
}
try catch 获取错误
put 的url 使用如下方式获取 body 数据:
$rsp = file_get_contents("php://input");
提交 form 表单:
$response = $client->request('POST',$url,[
    'form_params' => [
        'accountId' => $accountId,
        'orderId' => $orderId,
        'mac' => $mac
    ]
那么 $request->all() 或者 $_POST 即可获取值
注意:Laravel 或者其他框架一般会开启 CSRF验证,这么提交是不会通过验证的,可能会返回500 这个时候 被请求方应该 关闭这个验证
1.laravel 可以直接注释掉这个中间件 \App\Http\Middleware\VerifyCsrfToken::class,
2.laravel 在这个中间件里面添加排除路由
3.laravel 使用 api 接口
请求数据 json格式:
$response = $client->request('POST',$url,[
    'json' => ['foo' => 'bar']
]
此时请求方 $request->all() 或者 php://input 都能获取到数据  但是 $_POST 获取不到数据
例如结果打印:
request->all() 的数据
array (
  'foo' => 'bar',
)
$_POST 的数据
array (
)
file_get_contents("php://input")的数据:
{"foo":"bar"}
获取请求的 方法:
打印 $_SERVER['REQUEST_METHOD'] 即可
例如:
'REQUEST_METHOD' => 'DELETE',

Laravel 图片处理扩展包intervention/image的基本使用

首先是安装:

composer require intervention/image

安装他需要你的 php版本大于等于 5.4
还需要有 fileinfo 扩展,你可以通过 phpinfo() 查看扩展是否安装,也可以通过命令:

php --ri fileinfo 查看

我使用的是 lnmp 1.4 的一键安装,没有 fileinfo扩展
那么首先安装这个扩展:

1.首先确认你的系统中有 fileinfo 这个扩展源码,可以使用find 查找

find / -name fileinfo

2.如果没有,那么你可以再去php官网下载一份和你的php版本对应的源安装包
例如我的是 php 5.6.31

wget http://cn2.php.net/get/php-5.6.31.tar.gz/from/this/mirror
mv mirror php-5.6.31.tar.gz
tar -zxvf php-5.6.31.tar.gz
cd php-5.6.31/ext/fileinfo

此时就在 fileinfo 目录了。
3.你可以在这里直接执行命令

phpize

就会看到 configure文件
4.再执行如下命令:

./configure --with-php-config=/usr/local/php/bin/php-config
make && make install

此时完成了 fileinfo 扩展的编译工作
5.添加 fileinfo 到到 php.ini
修改 php.ini 添加 `extension=fileinfo.so`
6.重启 php-fpm 和 nginx 完成 fileinfo 扩展的安装

此时再执行

composer require intervention/image

就不会报错了
接下来laravel 添加这个服务
修改 config/app.php 在 providers 添加

Intervention\Image\ImageServiceProvider::class,

在 aliases 中添加

'Image' => Intervention\Image\Facades\Image::class,

这样就可以在 controller 里使用了

use Image;
// ...
// 代码
// ...
$img = Image::make('upload/a.png')->resize(50,100);  //修改尺寸
if(file_exists(public_path('new_image/'))){
}
else{
mkdir ( public_path('new_image/'), 0777);
}
$img->save('new_image/a_new.png',75); // 保存到别的路径,第二个参数设置压缩质量

上面的 make 传参是图片路径,这个路径是public 下的路径
在save 的时候首先要判断目录存在,如果不存在需要先创建,否则报错。如果是好几层的目录需要递归创建
参考函数:

public static function mkMutiDir($dir){
if(!is_dir($dir)){
if(!self::mkMutiDir(dirname($dir))){
return false;
}
if(!mkdir($dir,0777)){
return false;
}
}
return true;
}

Image::make 接收的参数不局限于图片文件 具体参考:
http://image.intervention.io/api/make
所以在 Laravel 中上传的文件也可以直接 make

$file = $request->file('img');
$img = Image::make($file);
//...

接下来你可以参考api 文档根据实际使用啦!

 

laravel 错误处理,接口错误返回json

Laravel 默认已经为我们配置好了错误和异常处理,我们在 App\Exceptions\Handler 类中触发异常并将响应返回给用户。
所有异常都由类App\Exceptions\Handler处理,该类包含两个方法:report和render
report方法只是将异常传递给异常被记录的基类,我们这里主要是针对 render 的修改:

先看代码:

public function render($request, Exception $exception)
{
    if($request->is('api/*')){
        $response = [];
        $error = $this->convertExceptionToResponse($exception);
        $response['status'] = $error->getStatusCode();
        $response['msg'] = 'something error';
        if(config('app.debug')) {
            $response['msg'] = empty($exception->getMessage()) ? 'something error' : $exception->getMessage();
            if($error->getStatusCode() >= 500) {
                if(config('app.debug')) {
                    $response['trace'] = $exception->getTraceAsString();
                    $response['code'] = $exception->getCode();
                }
            }
        }
        $response['data'] = [];
        return response()->json($response, $error->getStatusCode());
    }else{
        return parent::render($request, $exception);
    }
}

$request->is('api/*') 用于判断是否是 接口请求

$response 数组你可以依据你的接口返回格式统一一下。

laravel composer 扩展包开发(超详细)

laravel composer package develop
文章适用于laravel 包开发,当然如果你理解着完成一遍,就可以发现他也适用于 composer 扩展包开发,不是必须在laravel 下。
首先在 laravel 根目录创建文件夹 packages 这里放置我们准备创建的扩展包,这个目录只是暂时存放我们的扩展包代码,等我们开发完成配置好了,就不需要他了。
当然如果你不需要发布你的包,以后也可以就使用这个目录。packages 目录和 laravel 的 app 目录同级
然后进入packages 创建目录  aex 当然这个名字可以随意起(最好是作者的名之类的),
接着进入 aex 目录创建目录 packagetest 这个目录的名称最好是你的扩展包名称,有点意义。 我就是为了测试,所以就叫做 packagetest 好了
然后创建目录 src 这里就是我们放置代码的地方啦。
接着命令行下进入 packages/aex/packagetest 执行 composer init  他会一步步询问你要填写的信息:
1
执行完成你会在 packagetest 目录下看到 composer.json 内容和上图一致。 当然其实你也可以直接复制一个 composer.json 不需要 composer init
我的 composer.json 内容如下:
{
    "name": "aex/packagetest-for-laravel",
    "authors": [
        {
            "name": "aex",
            "email": "email@email.com"
        }
    ],
    "require": {}
}
你也可以根据 composer.json 的规则添加相应的其它配置
目前目录结构是这样的:
2
虽然你知道代码都在 src目录下,但是 laravel 不知道,所以你要告诉他,即配置 laravel 根目录的 composer.json
修改 autoload 改为类似如下:
"autoload": {
    "classmap": [
        "database"
    ],
    "psr-4": {
        "App\\": "app/",
        "Aex\\Packagetest\\": "packages/aex/packagetest/src/"
    }
},
然后创建服务:使用 artisan 命令
php artisan make:provider PackagetestServiceProvider
执行完成,laravel 在 app/Providers下会生成 PackagetestServiceProvider.php 然后你把他剪切到 你的 src目录:packages/aex/packagetest/src
同时修改代码的命名空间为你刚刚定义的:namespace Aex\Packagetest;  顺便把注册服务等都写完吧,完成代码如下:
<?php
namespace Aex\Packagetest;
use Illuminate\Support\ServiceProvider;
class PackagetestServiceProvider extends ServiceProvider
{
    /**
     * 服务提供者加是否延迟加载.
     *
     * @var bool
     */
    protected $defer = true; // 延迟加载服务
    /**
     * Bootstrap the application services.
     *
     * @return void
     */
    public function boot()
    {
        $this->loadViewsFrom(__DIR__ . '/views', 'Packagetest'); // 视图目录指定
        $this->publishes([
            __DIR__.'/views' => base_path('resources/views/vendor/packagetest'),  // 发布视图目录到resources 下
            __DIR__.'/config/packagetest.php' => config_path('packagetest.php'), // 发布配置文件到 laravel 的config 下
        ]);
    }
    /**
     * Register the application services.
     *
     * @return void
     */
    public function register()
    {
         // 单例绑定服务
        $this->app->singleton('packagetest', function ($app) {
            return new Packagetest($app['session'], $app['config']);
        });
    }
    /**
     * Get the services provided by the provider.
     *
     * @return array
     */
    public function provides()
    {
        // 因为延迟加载 所以要定义 provides 函数 具体参考laravel 文档
        return ['packagetest'];
    }
}
自问自答:
1.为什么创建的服务要放到src 下? -- 你要开发扩展包,放到laravel下面就不算扩展包了,你的包以后要给别人用,别人会统一安装到vendor下的,总不能单独把 service 文件也打包上传吧。
同理服务定义了 publish , 配置和视图不同系统需求肯定不一样,为了让人家修改,所以我们提供发布到laravel 原始视图和配置路径的方法,总不能让人家下载了你的到 到 vendor下修改吧。
2.那么 composer.json 里的命名空间为什么修改的是laravel 根目录的? -- 啪!多嘴!哦,不对,啪啪啪啪!!! 问的好!,这个我们还没讲完嘛,后面会给他提出来的,我们需要先跑通我们的代码,再完善成可发布的
接下来注册我们的服务到 config/app.php (你使用别人家的包都需要这步的)
添加一行 Aex\Packagetest\PackagetestServiceProvider::class
下一步添加配置文件:
在 src 目录下添加 config 目录然后添加文件 packagetest.php 内容如下:
<?php
return [
    'options' => [] // 只是为了演示
];
下一步创建我们的服务真正逻辑实现的代码: 在src目录下创建文件 Packagetest.php 内容如下:
<?php
namespace Aex\Packagetest;
use Illuminate\Session\SessionManager;
use Illuminate\Config\Repository;
class Packagetest
{
    /**
     * @var SessionManager
     */
    protected $session;
    /**
     * @var Repository
     */
    protected $config;
    /**
     * Packagetest constructor.
     * @param SessionManager $session
     * @param Repository $config
     */
    public function __construct(SessionManager $session, Repository $config)
    {
        $this->session = $session;
        $this->config = $config;
    }
    /**
     * @param string $msg
     * @return string
     */
    public function test_rtn($msg = ''){
        $config_arr = $this->config->get('packagetest.options');
        return $msg.' <strong>from your custom develop package!</strong>>';
    }
}
下一步创建视图文件:在src目录下添加views目录然后添加 packagetest.blade.php
@extends('layouts.app')
@section('content')
    <h1>Packagetest Message</h1>
    {{$msg}}
@endsection
下一步创建门面(Facades): 在src目录下添加 Facades目录然后添加 Packagetest.php
<?php
namespace Aex\Packagetest\Facades;
use Illuminate\Support\Facades\Facade;
class Packagetest extends Facade
{
    protected static function getFacadeAccessor()
    {
        return 'packagetest';
    }
}
然后命令行执行 :
composer dump-autoload
这样就能够使用命名空间 Aex\Packagetest 了,上面在 config/app.php 下添加的服务那行就真正生效了。(如果不执行 dump-autoload 运行程序会报错,说找不到类)
既然我们定义了门面 那么我们就可以为这个服务添加别名了。在 config/app.php  的 aliases 数组添加一行:
'Packagetest' => Aex\Packagetest\Facades\Packagetest::class
现在我们的目录结构类似:
3
至此代码其实就已经跑通了,但是还没有完全完成。我们先测试下试试,随便找个 controller 当然 route要定义好:例如:TestController.php
<?php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Packagetest;
class TestController extends Controller
{
    public function test(Request $request){
        $a = Packagetest::test_rtn('Aex');
        return view('Packagetest::packagetest',['msg'=>$a]);
    }
}
然后根据路由访问就可以看到效果啦。为什么说没有完全完成呢?因为 视图文件和 config 配置文件还在我们的包里定义,以后发布出去,包会在 vendor目录下,这些文件不应该在vendor下修改
所以命令行执行:
php artisan vendor:publish --provider="Aex\Packagetest\PackagetestServiceProvider"
//  --provider 参数指定了要发布的服务 你也可以省略来发布所有的
发布后你就会在 laravel 本身的 config目录 和 views/vendor/packagetest 下看到你的文件了,也就可以按照需求随意修改了。
最后我们说 修改的laravel 的composer.json ,我们要发布我们的包,让所有人都能使用 composer 安装,那么执行如下步骤
去掉 添加的 那行 "Aex\\Packagetest\\": "packages/aex/packagetest/src/" 然后 修改 packages/aex/packagetest/composer.json
添加 autoload:
"autoload": {
    "psr-4": {
        "Aex\\Packagetest\\": "src/"
    }
}
这样包就是一个完整独立的包了,然后把他提交到你的 GitHub 上。
提交到 github 上的我的目录结构是:
4
我的地址是:https://github.com/ALawating-Rex/packagetest-for-laravel 有需要参考的可以参考下。
接着就是把包提交到 packagelist了, 网址: https://packagist.org/ 如果没有账户则注册一个
然后点击 submit ,填写项目URL,点击check
5
成功后点击  submit 就完成了。 至此你的包就可以像其它人的一样通过 composer require 安装了 6
如上图,两个箭头分别代表了包名称 和 版本
所以安装这个包的时候你的 composer.json 在require可以加这样一行:
"aex/packagetest-for-laravel": "dev-master"
安装之前我们先把我们之前开发的这个包都删除吧,就假设是一个别人的 laravel 框架要用我们的包: 删除 packages 文件夹
删除 config/packagetest.php
删除 resources/views/vendor/packagetest
conifg/app.php 里面删除添加的服务和别名
controller 里的改动就保留吧,因为安装完还是要这么写一遍 最后执行 composer dump-autoload
下面安装这个自定义包吧: composer update aex/packagetest-for-laravel
然后添加服务: 修改 config/app.php 添加
Aex\Packagetest\PackagetestServiceProvider::class
和别名的配置:
'Packagetest' => Aex\Packagetest\Facades\Packagetest::class
执行 composer dump-autoload
发布资源文件: php artisan vendor:publish --provider="Aex\Packagetest\PackagetestServiceProvider"
测试通过 大功告成!
额外的:
1.在 packagelist 你的这个包页面可以看到提示了 Set Up GitHub Service Hook 你可以按照提示办法安装,安装完成后,一旦你的项目有push,这里就会跟着更新。
2.还是 packagelist 页面,可以看到目前你只有  dev-master 版本,假设你需要其它的版本 你可以去你的 github 项目添加 tag
git tag 1.0.0 && git push --tags
这样composer require 就可以指定别的版本了。
3.为了别人能够更加清晰的使用你的包,完善你的 Readme 吧
4.不是必须laravel 框架,单纯的 composer 扩展包开发也是按照这个步骤来,只不过需要你摘出 laravel 结合的部分。

laravel blade 模版引擎指令详解和使用举例

laravel blade 模版引擎
laravel blade 模版引擎
定义片段
@section('content')
   xxxx
@show
show 表示同时显示
@section('ccc')
     xxxx
@endsection
使用 endsection 不会主动显示,只有 yield 指定的地方 和 @section ...@show 的地方会显示
显示指定片段的内容
@yield('content')
扩展布局 (继承)
// 指定子页面所继承的布局
@extend('layouts.app')
此时 这个 子页面(视图)将会使用 @section 指令注入内容到布局的片段中
子页面和父页面都有定义 @setion('content') 片段,则子页面会覆盖父页面
如果想使用追加可以使用 @parent
@section('content')
   @parent
   new - xxxx
@show
@parent指令在渲染的时将被替换为布局中的内容
注:
使用 section ... show  然后又使用了 section ... endsection (无论是在布局还是子视图中)那么show 里面的会被 endsection 定义的 覆盖
想要追加 那么要在 endsection 区添加 @parent
如果是
section ... show
section ... endsection
section ... show
那么两处show 都会被 endsection 里的内容替代。 但是要注意此时 第二个 section...show 会跑到页面的最上面,可以通过查看网页源代码发现。
 
输出 php 代码有以下方式:
1.{{ $var }}
2.{!! $var !!}
3.<?php echo $var; ?>
第三种就不用说了,第一种和第二种其实都是相当于 echo 但是第一种是 echo e($var) 调用了辅助函数e()  --> 定义:
function e($value)
{
    if ($value instanceof Htmlable) {
        return $value->toHtml();
    }
    return htmlspecialchars($value, ENT_QUOTES, 'UTF-8', false);
}
即有经过 html实体字符转换
第二种就是 echo $var 了  具体这些都可以参考 storage/framework/views/下编译出来的文件查看 原生内容 。
如果想让 {{}} 不被 slade 引擎转义 那么可以使用 @符号 @{{$var}} 这样就会原样输出
如果很大一块代码需要原样输出:  verbatim 指令
@verbatim
    <div class="container">
        Hello, {{ name }}.
    </div>
@endverbatim
组件和插槽:
组件和插槽可以是 section 和 layout应用更灵活,且 也很容易理解。页面需要复用的东西可以通过 组件和插槽实现,例如:
我们在 controller 里定义要渲染的视图是 test 即 return view('test')
然后在 test.blade.php 里首先 extends('layouts.app') 然后需要引入提示消息的视图,明显这个可以在各个页面复用,那么可以使用 组件和插槽的方式:
test.blade.php:
@extends('layouts.app')
@section('content')
    <h1>test blade2</h1>
    @parent
    <hr/>
    @component('alert',['foo' => 'bar','tt'=>'TTTTHHH'])
        aaaa
        @slot('title')
            Forbidden
        @endslot
        @slot('foo')
            barbarbar
        @endslot
        @slot('aex','哈哈哈哈')
        You are not allowed to access this resource!
    @endcomponent
@endsection
alert.blade.php:
<div class="alert alert-danger">
    <div class="alert-title">{{ $title }}</div>
    {{ $slot }}
    <h1>{{$foo}}</h1>
    <h1>{!! $foo !!}</h1>
    <h2>{{$tt}}</h2>
    <h3>{{$aex}}</h3>
</div>
那么由此 上面的 section 会被放到 layouts.app 里 yield 定义的content 这些都是之前的概念了。
componet 定义了 alert 于是就会去渲染 alert.blade.php 后面的数组可以不定义,定义了就是往alert视图注入变量 即:$foo = 'bar', $tt = 'TTTTHHH' 这样就可以做到把 controller里的变量传递给 alert视图了
后面的 @slot 指令其实也是相当于 $title = 'Forbidden'
还可以写为 @slot('aex','哈哈哈哈')  即 $aex = '哈哈哈哈';
最后你会发现还有不再 @slot指令里的内容 即 aaaa 和 You are not allowed to access this resource! 他们会被放到 alert 模版 $slot 指定的地方。
感兴趣的仍然可以去看下 framework 编译的原始文件 ,大致会看到 $__env->startComponent('alert',['foo' => 'bar','tt'=>'TTTTHHH']) ... 这样的内容,
然后看下 startComponent 的定义以及其它的函数定义 就大致理解工作流程了(主要使用了 ob_start 和 ob_get_clean 等)。 定义文件在:\vendor\laravel\framework\src\Illuminate\View\Concerns\ManagesComponents.php
子视图:
Blade 的 @include 指令允许你很轻松地在一个视图中包含另一个 Blade 视图,所有父级视图中变量在被包含的子视图中依然有效:
<div>
    @include('shared.errors')
    <form>
        <!-- Form Contents -->
    </form>
</div>
尽管被包含的视图可以继承所有父视图中的数据,你还可以传递额外参数到被包含的视图:
@include('view.name', ['some' => 'data'])
堆栈:
前端页面  js我们通常希望放到页脚,不同页面引入的 js 又不一样,想要做到这点就可以使用堆栈功能。
例如在布局文件 app.blade.php 最下面 </body> 上面加入 @stack('scripts') 然后在你要渲染的视图 例如 test.blade.php 将js推送入栈即可
@push('scripts')
    <script type="text/javascript" src="/jquery.min.js"></script>
@endpush
服务注入:
视图中大部分变量是通过 controller 传递的,但是有的时候我们仍需要调用 laravel 的一些类获取相应的值,那么可以使用 @inject 指令
@inject 指令可以用于从服务容器中获取服务,传递给 @inject 的第一个参数是服务将要被分配到的变量名,第二个参数是要解析的服务类名或接口名:
@inject('metrics', 'App\Services\MetricsService')
<div>
    Monthly Revenue: {{ $metrics->monthlyRevenue() }}.
</div>
你也可以这样使用:
<?php
    var_dump(App\User::where('id',1)->first()->toArray());
?>