github的辅助项目们

时常在github项目上看到类似下面这样的小标签,用于展示项目的一些信息。

今天稍微接触了一下这些(小)项目。目前还没有在blog上使用,过段时间会尝试一下。

Shields.io

提供高质量Github项目进度角标图片的API.shields.io 。引用起来也非常简单

<div id="container">
    <img src="http://progressed.io/bar/28?title=progress" alt="">
    <img src="http://progressed.io/bar/30?title=nice" alt="">
    <img src="http://progressed.io/bar/60?title=极客标签" alt="">
    <img src="https://img.shields.io/teamcity/http/teamcity.jetbrains.com/s/bt345.svg" alt="">
    <img src="https://img.shields.io/pypi/dw/Django.svg" alt="">
    <img src="https://img.shields.io/badge/soul-GBTAG-red.svg" alt="">
</div>
<script type="text/javascript" src="http://cdn.gbtags.com/jquery/1.11.1/jquery.min.js"></script>

显示出来就是这个样子:

总的说来就是显示项目构建、下载、版本号、sns情况和其他五花八门的信息显示图标。

gitter.im

Gitter.im是一款支持Markdown的针对开发者的即时通讯软件。

  • Gitter.im 基于 Github 进行构建,紧密地集成到您的 organisations, repositories, issues 和 activity。
  • Gitter.im还提供与 Trello, Jenkins, Travis CI, Heroku, Sentry, BitBucket, HuBoard, Logentries, Pagerduty 以及 Sprintly 的集成。同样支持自定义的 webhook ,为集成提供了开源库以及灵活的API。
  • 支持MarkDown语法
  • 免费用户就可拥有 无限制的公开及私密聊天室数量
  • 免费用户就可拥有 无限制的历史聊天记录
  • 拥有Macos,Linux,Windows,苹果IOS,安卓Andriod APP客户端,还有几十个第三方APP。

Go Report Card

Go_Report_Card,一个可以为你的开源 Go 代码生成质量报告的网站,挺不错的,利用的常见的几个工具,golint, go vet等。

microbadger

microbadger是一个管理你的Docker镜像的工具。

Coveralls

使用coveralls在代码自动化测试时统计测试覆盖率

CI持续集成平台

appveyor

随着SaaS的兴起,appveyor把持续集成搬到了云端,我们无需架设自己的CI服务器,只需注册一个账号,然后把GitHub, BitBucket或者TFS 连上AppVeyor就可以了

travis-ci.org

Travis CI 是目前新兴的开源持续集成构建项目,它与jenkins,GO的很明显的特别在于采用yaml格式,简洁清新独树一帜。目前大多数的github项目都已经移入到Travis CI的构建队列中。Travis-CI 使用 PostgreSQL 数据库。

circleci

CircleCI 是又一个持续集成平台。

参考资料


转载 | Composer 入门

前言: 最近总结了好多和 composer 相关的文章。这一篇对 composer 做个简单介绍。文章大部分来源于Composer 中文文档

对于现代语言而言,包管理器基本上是标配。Java 有 Maven,Python 有 pip,Ruby 有 gem,Nodejs 有 npm。PHP 的则是 PEAR,不过 PEAR 坑不少:

依赖处理容易出问题
配置非常复杂
难用的命令行接口

composer 也是 PHP 用来管理依赖关系的工具。它做的如此之好,以至于如果你只是纯粹地进行 php 开发,在平时使用中对几乎可以忽略 composer。 你可以在自己的项目中声明所依赖的外部工具库,Composer 会帮你安装这些依赖的库文件。它实际上包含了两个部分:ComposerPackagist

Composer 是由 Jordi Boggiano 和 Nils Aderman 创造的一个命令行工具,它的使命就是帮你为项目自动安装所依赖的开发包。Composer 包含了一个依赖解析器,用来处理开发包之间复杂的依赖关系;另外,它还包含了下载器、安装器等有趣的东西。 Packagist 是 Composer 的默认的开发包仓库。你可以将自己的安装包提交到 packagist,当你在自己的 Git 仓库中新建了 tag 或更新了代码,packagist 都会自动构建一个新的开发包。

安装 Composer

Composer 需要 PHP 5.3.2+ 才能运行。

$ curl -sS https://getcomposer.org/installer | php

这个命令会将 composer.phar 下载到当前目录。PHAR(PHP 压缩包)是一个压缩格式,可以在命令行下直接运行。

你可以使用 –install-dir 选项将 Composer 安装到指定的目录,例如:

$ curl -sS https://getcomposer.org/installer | php -- --install-dir=bin

当然也可以进行全局安装:

$ curl -sS https://getcomposer.org/installer | php
$ mv composer.phar /usr/local/bin/composer

在 Mac OS X 下也可以使用 homebrew 安装:

brew tap josegonzalez/homebrew-php  
brew install josegonzalez/php/composer  

不过通常情况下只需将 composer.phar 的位置加入到 PATH 环境变量就可以,不一定要全局安装。

声明依赖

在项目目录下创建一个 composer.json 文件,指明依赖,比如,你的项目依赖 monolog:

{
    "require": {
        "monolog/monolog": "1.2.*"
    }
}

安装依赖

安装依赖非常简单,只需在项目目录下运行:

composer install   如果没有全局安装的话,则运行:

php composer.phar install  

自动加载

Composer 提供了自动加载的特性,只需在你的代码的初始化部分中加入下面一行:

require 'vendor/autoload.php';  

模块仓库

packagist.org 是Composer的仓库,很多著名的 PHP 库都能在其中找到。你也可以提交你自己的作品。

高级特性

Composer 还有一些高级特性,虽然不是必需的,但是往往能给 PHP 开发带来方便。

几个小技巧

1. 仅更新单个库

composer update foo/bar  

2. 不编辑composer.json的情况下安装库

你可能会觉得每安装一个库都需要修改composer.json太麻烦,那么你可以直接使用require命令。

composer require "foo/bar:1.0.0"  

这个方法也可以用来快速地新开一个项目。init命令有–require选项,可以自动编写composer.json:(注意我们使用-n,这样就不用回答问题)

$ composer init --require=foo/bar:1.0.0 -n
$ cat composer.json
{
    "require": {
        "foo/bar": "1.0.0"
    }
}

3. create-project

composer create-project doctrine/orm path 2.2.0  

这会自动克隆仓库,并检出指定的版本。克隆库的时候用这个命令很方便,不需要搜寻原始的URI了。

4. 考虑缓存,dist包优先

最近一年以来的Composer会自动存档你下载的dist包。默认设置下,dist包用于加了tag的版本,例如”symfony/symfony”: “v2.1.4”,或者是通配符或版本区间,”2.1.*“或”>=2.2,<2.3-dev”(如果你使用stable作为你的minimum-stability)。

dist包也可以用于诸如dev-master之类的分支,Github允许你下载某个git引用的压缩包。为了强制使用压缩包,而不是克隆源代码,你可以使用install和update的–prefer-dist选项。

下面是一个例子(我使用了–profile选项来显示执行时间):

$ composer init --require="twig/twig:1.*" -n --profile
Memory usage: 3.94MB (peak: 4.08MB), time: 0s

$ composer install --profile
Loading composer repositories with package information  
Installing dependencies  
  - Installing twig/twig (v1.12.2)
    Downloading: 100%

Writing lock file  
Generating autoload files  
Memory usage: 10.13MB (peak: 12.65MB), time: 4.71s

$ rm -rf vendor

$ composer install --profile
Loading composer repositories with package information  
Installing dependencies from lock file  
  - Installing twig/twig (v1.12.2)
    Loading from cache

Generating autoload files  
Memory usage: 4.96MB (peak: 5.57MB), time: 0.45s  

这里,twig/twig:1.12.2的压缩包被保存在~/.composer/cache/files/twig/twig/1.12.2.0-v1.12.2.zip。重新安装包时直接使用。

5.为生产环境作准备

在部署代码到生产环境的时候,别忘了优化一下自动加载:

composer dump-autoload --optimize   安装包的时候可以同样使用--optimize-autoloader。不加这一选项,你可能会发现20%到25%的性能损失。

如果你需要帮助,或者想要了解某个命令的细节,你可以阅读官方文档或者中文文档,也可以查看JoliCode做的这个交互式备忘单

参考资料


php 数组增加元素的方法 array_push 和 array_merge

本文的起因是今天需要给一个数组添加成员,一个是无序数组,直接往里扔就可以,另一个是key-value形式的数组。

无序数组只要array_push即可,key-value数组如果数量少,也可以用 $data['pussy'] = 'wagon'形式。

array_push(array,value1,value2…)

参数	描述
array	必需。规定数组。
value1	必需。规定要添加的值。
value2	可选。规定要添加的值。

例子:

$config = require_once __DIR__ . '/../vendor/xxx.php';
array_push($config['providers'],
    xxx\Providers\HttpClientServiceProvider::class,
    xxx\Providers\SmsServiceProvider::class,
    xxx\Providers\QrCodeServiceProvider::class,
    \Intervention\Image\ImageServiceProvider::class,
    xxx\Providers\ImageServiceProvider::class,
    xxx\Providers\WordSegmentServiceProvider::class,
    xxx\Providers\WechatServiceProvider::class,
    xxx\Providers\RecommendServiceProvider::class,
    Ignited\LaravelOmnipay\LaravelOmnipayServiceProvider::class
);

array_merge(array1,array2,array3…)

参数	描述
array1	必需。规定数组。
array2	可选。规定数组。
array3	可选。规定数组。

例子接上:

$config['aliases'] = array_merge($config['aliases'], [
        'HttpClient' => xxx\Facades\HttpClient::class,
        'Sms' => xxx\Facades\Sms::class,
        'QrCode' => xxx\Facades\QrCode::class,
        'Image' => \Intervention\Image\Facades\Image::class,
        'ImageUpload' => xxx\Facades\Image::class,
        'WordSegment' => xxx\Facades\WordSegment::class,
        'Recommend' => xxx\Facades\Recommend::class,
        'Wechat' => xxx\Facades\Wechat::class,
        'Omnipay' => Ignited\LaravelOmnipay\Facades\OmnipayFacade::class
    ]
);

使用 satis 搭建一个私有的 Composer 包仓库

在日常php开发中可能需要使用大量的composer包,大部份都可以直接使用,但公司内部有一些与业务相关的包,是不能公开的,这时候我们就需要搭建一个公司内部使用的composer仓库。

composer官方提供的工具有satis和toran proxy。 satis的搭建相对简单一些,于是我选用satis进行搭建。它的文档在composer 以及 github

1. 建立项目

使用 Composer 自带的建项目功能,这个相当于 git clone + composer install + 运行 post-install 脚本。

composer create-project composer/satis my-satis --stability=dev --keep-vcs

2. 建立配置文件

在 satis 项目目录下建立 satis.json 文件

{
  "name": "仓库名称",
  "homepage": "http://satis仓库地址",
  "repositories": [
    { "type": "vcs", "url": "https://github.com/mycompany/privaterepo" },
    { "type": "vcs", "url": "http://svn.example.org/private/repo" },
    { "type": "vcs", "url": "https://github.com/mycompany/privaterepo2" }
  ],
  "require-all": true
}

注意:仓库名称需要和仓库里 composer.json 的 name 定义一致,和路径没什么关系,不然就会找不到。

因为加入私有源的仓库本身可能也有依赖,require-all 会把这些依赖的信息也抓进来。如果不需要的话,可以指定某个仓库,甚至某个版本:

{
  "name": "仓库名称",
  "homepage": "http://satis仓库地址/",
  "repositories": [
    { "type": "vcs", "url": "https://github.com/mycompany/privaterepo" },
    { "type": "vcs", "url": "http://svn.example.org/private/repo" },
    { "type": "vcs", "url": "https://github.com/mycompany/privaterepo2" }
  ],
  "require": {
    "company/package": "*",
    "company/package2": "*",
    "company/package3": "2.0.0"
  }
}

3. 生成仓库列表

php bin/satis build satis.json public/

4. 配置nginx

总之把访问地址的根目录放在public文件夹下。

5. 在其它项目中使用私有源

只需要在项目的 composer.json 文件的根上添加

{
  "repositories": [
    {
      "type": "composer",
      "url": "http://satis仓库地址/"
    }
  ],
  "require": {
    "company/package": "1.2.0",
    "company/package2": "1.5.2",
    "company/package3": "dev-master"
  }
}

然后执行composer update即可

注意:源里面只有“仓库列表”,并没有真的同步代码仓库过来,所以下载还要走托管代码的机器,比如 GitHub,内部 GitLab 等。

如果从 clone 速度太慢了,我们也可以缓存在我们的仓库中。

在satis.json中增加

{
    "archive": {
        "directory": "dist",
        "format": "tar",
        "prefix-url": "http://packages.dev.com/",
        "skip-dev": true
    }
}

directory: 必需要的,表示生成的压缩包存放的目录,会在我们build时的目录中
format: 压缩包格式, zip(默认) tar
prefix-url: 下载链接的前缀的Url,默认会从homepage中取
skip-dev: 默认为假,是否跳过开发分支
absolute-directory: 绝对目录
whitelist: 白名单,只下载哪些
blacklist: 黑名单,不下载哪些
checksum: 可选,是否验证sha1

再次生成

php bin/satis build satis.json public/

会发现public目录多了一个dist目录,里面有很多tar的压缩包,这就是我们的package。 之后再执行composer update就会发现快了很多。

参考资料


selenium2 入门 - 基于php

Selenium 用于自动化测试,它有助于自动化Web应用程序测试。本文介绍它的快速入门配置(php版本)与一个很简单的php爬虫应用。

Composer 安装 Selenium:

composer require facebook/webdriver

安装selenium

本机安装

  • 下载Selenium Server并启动:

    下载Selenium Standalone Server:http://www.seleniumhq.org/download/

    安装java jdk后,运行如下命令:

    java -jar selenium-server-standalone-3.0.1.jar
    
  • 下载浏览器插件

    selenium 支持多种浏览器,我目前使用的是chrome。http://chromedriver.storage.googleapis.com/index.html?path=2.27/

    下载解压,你会得到一个 chromedriver.exe 文件,放到 chrome 的安装目录下(我的:C:\Program Files (x86)\Google\Chrome\Application\),然后在 path 环境变量中添加 chrome 的安装目录。

docker安装

docker run -d --name chrome --rm -p 4444:4444 -p 5900:5900 selenium/standalone-chrome-debug

上面这条命令的参数含义如下:

  • -d, 表示不附着容器,即容器在后台运行
  • –name 是给容器定义一个名称;
  • –rm 容器运行结束后即删除,方便调试使用
  • -p 4444:4444 暴露宿主机的4444端口到容器的4444端口,提供 webdriver 服务;
  • -p 5900:5900 暴露宿主机的5900端口,提供 VNC 远程桌面服务,如果是在 Mac 上运行,有可能5900端口已使用,可以换为5901端口,写法是 -p 5901:5900

可以用 VNC viewer 观看浏览器运行的情况。

运行测试代码

打开命令提示符,运行后边的文件 php bilibili.php 命令,最后打印了哔哩哔哩顶部的8个视频。

// bilibili.php
<?php
namespace Facebook\WebDriver;

use Facebook\WebDriver\Remote\DesiredCapabilities;
use Facebook\WebDriver\Remote\RemoteWebDriver;

require_once('vendor/autoload.php');

header("Content-Type: text/html; charset=UTF-8");
$waitSeconds = 15;  //需等待加载的时间,一般加载时间在0-15秒,如果超过15秒,报错。
$host = 'http://localhost:4444/wd/hub'; // this is the default
$capabilities = DesiredCapabilities::chrome();
$driver = RemoteWebDriver::create($host, $capabilities, 5000);
$baseUrl = 'http://www.bilibili.com/';
$driver->get($baseUrl);

echo consoleText($driver->getTitle()) . "\n";    //cmd.exe中文乱码,所以需转码

$topLists = $driver->findElement(WebDriverBy::className('container-top-wrapper'))->findElement(WebDriverBy::className('top-list-wrapper'))->findElements(WebDriverBy::tagName('li'));

foreach ($topLists as $topLi) {
    $itemContent = $topLi->findElement(WebDriverBy::tagName('a'));
    echo consoleText($itemContent->getAttribute('title')) . ' : ' . consoleText($itemContent->getAttribute('href')) . "\n";
}


//关闭浏览器 $driver->quit();

function consoleText($text, $pageEncoding = '', $consoleEncoding = '')
{
    // windows
    if (!$consoleEncoding) {
        if (stristr(php_uname('s'), 'win')) {
            $consoleEncoding = "GBK";
        } else {
            $consoleEncoding = 'UTF-8';
        }
    }
    return exchangeEncoding($text, $pageEncoding, $consoleEncoding);
}

function exchangeEncoding($text, $pageEncoding = '', $targetEncoding = 'UTF-8')
{
    if (!$pageEncoding) {
        $pageEncoding = mb_detect_encoding($text, array("ASCII", 'UTF-8', "GB2312", "GBK", 'BIG5'));
    }

    if ($pageEncoding != $targetEncoding) {
        return mb_convert_encoding($text,$targetEncoding,$pageEncoding);
    }

    return $text;
}

//切换至最后一个window
function switchToEndWindow($driver)
{

    $arr = $driver->getWindowHandles();
    foreach ($arr as $k => $v) {
        if ($k == (count($arr) - 1)) {
            $driver->switchTo()->window($v);
        }
    }
}

?>

参考资料


php 获取编码和转换编码

做爬虫抓取页面的时候,常常有非utf-8的混入,包括gbk gb2312 甚至是 Big5,需要转换成我们期望的格式。 同时,Windows与其他操作系统也不同。普通的Linux和Mac都是原生使用utf-8的编码格式,而中文的windows用的则是gbk格式。因此针对不同系统的终端输出(console,cmd),我们也需要进行编码转换。

看代码说话:

function exchangeEncoding($text, $pageEncoding = '', $targetEncoding = 'UTF-8')
{
    if (!$pageEncoding) {
        $pageEncoding = mb_detect_encoding($text, array("ASCII", 'UTF-8', "GB2312", "GBK", 'BIG5'));
    }

    if ($pageEncoding != $targetEncoding) {
        return mb_convert_encoding($text,$targetEncoding,$pageEncoding);
    }

    return $text;
}

function consoleText($text, $pageEncoding = '', $consoleEncoding = '')
{
    // windows
    if (!$consoleEncoding) {
        if (stristr(php_uname('s'), 'win')) {
            $consoleEncoding = "GBK";
        } else {
            $consoleEncoding = 'UTF-8';
        }
    }
    return exchangeEncoding($text, $pageEncoding, $consoleEncoding);
}

使用 php_uname() 判断操作系统类型

/**
 *       'a':  返回所有信息
 *       's':  操作系统的名称,如FreeBSD
 *       'n':  主机的名称,如cnscn.org
 *       'r':  版本名,如5.1.2-RELEASE
 *       'v':  操作系统的版本号
 *       'm': 核心类型,如i386
 */
function php_uname ($mode = null) {}

运行 php_uname(), 在我本机 Windows 中,返回类似如下的数据

Windows NT KELU-PC 10.0 build 10586 (Windows 10) AMD64

在 Linux 服务器中则如下

Linux debian 4.8.6-x86_64 #1 SMP Tue Nov 1 14:51:21 EDT 2016 x86_64

使用 mb_detect_encoding 判断字符编码

function mb_detect_encoding ($str, $encoding_list = null, $strict = null) {}

使用 mb_convert_encoding 转换字符编码

function mb_convert_encoding ($str, $to_encoding, $from_encoding = null) {}

参考资料