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) {}

参考资料


Chrome 插件vimium —— vim党的福音

使用vimium已经很长时间了,然而每次应用仅限于hjkl几个上下左右键和KJ标签页操作这种最低级的操作。实际上vimium有很多实用的快捷键。 这几天换了新的办公地点,除了熟悉vimium这个插件外,索性给自己再来点新的感觉——使用左手鼠标。三天过去了,慢慢习惯了,确实不错。倒不是因为效率上带来的提高,而是由此带来的新鲜感,将平日的疲惫和懈怠感一扫而空。

最常用

hjkldu 页面内移动 JK 标签页切换 HL 后退前进

Command Note
O 在新标签页中打开 URl、书签或历史记录
t 创建一个新标签页
x 关闭当前标签页

页面导航

Command Note
j, <c-e> 向下滚动
k, <c-y> 向上滚动
h 向左滚动
l 向右滚动
gg 滚动到页面顶部
G 滚动到页面底部
zH 滚动到页面最左边
zL 滚动到页面最右边
d 向下滚动(相当于 PageDown 键)
u 向上滚动(相当于 PageUp 键)
r 重载页面
gs 查看页面源代码
yy 复制当前 URL 到剪贴板
yf 复制一个 URL 链接到剪贴板
p 打开剪贴板中的 URL 到当前标签页
P 打开剪贴板中的 URL 到新标签页
gu 跳转到当前 URL 的上一层
gU 跳转到当前 URL 的最高层
i 进入插入模式
v Enter visual mode (beta feature) (enterVisualMode)
V Enter visual line mode (beta feature) (enterVisualLineMode)
gi 焦点第一个文本输入框。使用 tab 可以在文本输入框之间循环跳转
f 在当前标签页中打开一个链接
F 在新标签页中打开一个链接
<a-f> 在新标签页中打开多个链接
[[ Follow the link labeled previous or < (goPrevious)
]] Follow the link labeled next or > (goNext)
gf Cycle forward to the next frame on the page (nextFrame)
gF Select the tab’s main/top frame (mainFrame)
m 创建新标记

使用 Vomnibar

Command Note
o 打开 URl、书签或历史记录
O 在新标签页中打开 URl、书签或历史记录
T 搜索已打开的标签页
b 打开书签
B 在新窗口中打开书签
ge 编辑当前 URL
gE 编辑当前 URL 并在新标签页中打开

使用查询

Command Note
/ 进入查询模式
n 下一个已查询到的值(页面内循环查找)
N 上一个已查询到的值(页面内循环查找)

导航历史

Command Note
H 根据浏览历史后退一页
L 根据浏览历史前进一页

标签操纵

Command Note
K, gt 向右移动一个标签页
J, gT 向左移动一个标签页
g0 移动到第一个标签页
g$ 移动到最后一个标签页
t 创建一个新标签页
yt 复制当前标签页
x 关闭当前标签页
X 恢复已关闭的标签页
W 将标签页移动到新窗口
<a-p> 固定/取消固定当前标签页
« 向左移动标签页
» 向右移动标签页

其他

Command Note
? 显示帮助

参考资料


postgresql 连接报错 - no pg_hba_conf entry for host

最近换了办公环境,发现内部测试时使用 postgres 无法正常连接数据库。 使用工具连接时报错

connect to PostgreSQL server: FATAL: no pg_hba.conf entry for host "4X.XXX.XX.XXX", user "userXXX", database "dbXXX".

在维护 PostgreSQL 库时,pg_hba.conf 属于认证文件,在业务服务器出现调整,或增加应用服务器时,需要增加 pg_hba.conf 的 IP 签权信息。 另外pg_hba.conf 文件的更改对当前连接不影响,仅影响更改配置之后的新的连接。

如果 Postgresql 在 windows 下安装,使用安装时附带的 pgAdmin 进行修改即可。

一般该文件位于

C:\my_pp\PostgreSQL\9.4\data\pg_hba.conf

如果是 Linux 环境,使用 find 全局查找也能查出来。按照文件example修改即可。因为内网环境,也就没所谓了,让所有链接都能通过,即 0.0.0.0/0

local   all             all                                     peer
# IPv4 local connections:
host    all             all             0.0.0.0/0            trust
host    all             all             samenet                 trust
# IPv6 local connections:
host    all             all             ::1/128                 trust

pg 的几个基本概念

pg 的几个基本概念

  • 实例(instance):一台机器上可以跑多个实例,每个实例要占用单独的端口,默认只跑一个实例,默认端口是5432
  • 数据库(database):一个实例可以包含多个数据库
  • 模式(schema):一个数据库可以包含多个模式,模式之间的命名不会冲突,默认模式是public
  • 对象(object):模式里包含的所有东西都是对象,包括表、视图、索引、函数等等

参考资料