分类 技术 下的文章

科普科学,便捷上网

鉴于很多朋友不大清楚科学上网的原理,这里简单介绍一下。
大陆墙是为了祖国社会稳定,使大众免受外来不良思想的影响而建立的。
墙外有一些网站,我们没办法访问,尽管他们的产品很棒。
kexueshangwang1.png
计算机网络中,有一种架构叫做代理。
你直接访问不了的,可以交给能访问得了的人(软件)帮你访问,再转达给你,问题解决!
上图的Shadowsocks(以下简称ss)便是你的帮手,它可以代理你的网络请求,使你能够Google一下。

下面说一下技术逻辑:

  1. ss提供网络代理服务,同时配置系统网络代理。
  2. 当我们用浏览器打开一个网址A时,浏览器会读取 系统的网络配置 或 浏览器自身的网络配置,从而得知,网址A应该直接访问 还是 通过代理来访问。
  3. 用已确认出的方式访问吧
    kexueshangwang2.png

完。

对PHP连接MySQL和其他数据库方式的理解

PHP/MySQL是主流的应用开发搭配方式,印象中PHP支持使用很多种数据库,而且MySQL就有mysql、mysqli、pdo三种API可用。本文旨在从PHP数据库访问设计的思路为轴,简单的捋清这些关系。

PHP手册中《数据库扩展》一章有两部分:数据库抽象层、针对各数据库系统对应的扩展,已经是足够的说明了,要更深刻的理解可去研读。

首先,直接的想法是,PHP应该为不同的数据库实现不同的数据库抽象层,调用客户端库API来使用DBMS。如下图:
1.png

然后,考虑这个场景:当PHP应用写好后,环境数据库不同时,就要用对应的数据库抽象层重写项目所有数据库相关代码。所以能否把访问抽象出来,用不同数据库时,只要切换不同实现就ok了。如下图:
2.png

最后,主流选用MySQL当然是既可以使用mysql、mysqli两种数据库抽象层,又可以使用PDO数据访问抽象层(须安装PDO_MYSQL扩展实现PDO接口)。如下图:
3.png

当然任何一个数据库抽象层,都要在PHP编译时都要指定数据库的客户端库以使用数据库服务器。以MySQL为例,推荐用mysqlnd库,配置项:--with-mysqli=mysqlnd --with-pdo-mysql=mysqlnd --with-mysql=mysqlnd

现在是不是清晰些了呢?

Don't Repeat Yourself - 编程开发原则

1. Do not repeat yourself(重构、抽象...)

2. 工具能做的麻烦事,不要自己做(格式化、语法检查...)

IDE能做的事儿,不要浪费自己时间去做。
把时间用在代码逻辑、性能考虑上。

3. 接口方法,只做应该做的事,不多不乱,保持原数据结构/顺序。

例子:
任务页面有召集人(多个)的列表,是后台运营人员填写的,有时第一次访问时顺序有混乱,之后访问右正常了。觉得很奇怪,看代码知道了 原来是缓存搞的鬼!

背景:
微博的内容产品几乎都有好友/粉丝 与 物 的关系,所以通过array(uid,uid,uid,...)取用户详细信息的方法,是早已抽象好的,逻辑是:对传进来的array进行缓存查找,得到已缓存的条目未命中的uid列表,再以此查库将返回结果追加到已缓存的条目,返回结果。

策略不错,但有个小问题,参数传进来可能是有顺序的,所以期望的结果集的顺序应该是与参数一致的。
有两个办法,1改接口、2重新排序,因为作为调用方不便改接口,所以重新排序!

怎么排呢,经同事指正,几行代码:

$users = Dr_User::get_user_infos($uids, false);//结果集已经乱序了

$flip_users = array_flip($uids);//反转uid列表,array(uid=>0,uid=>1,...),再遍历users存到对应键上
foreach ($users as $user) {
    $flip_users[$user['id']] = $user;
}
$users = $flip_users;
unset($flip_users);

结论:如果很多调用方都有保持顺序的需求,接口的设计就该添加一个参数以控制结果是否保持顺序。

4. 务必打开所有错误显示,包括NOTICE级

5. 变量的检查,统一在view controller里做

6. 明确开发/生产环境...

...

Tips

  1. 新增/修改时,sql语句慎用replace,当字段中有主键和唯一键时,若已有记录,修改的实际操作是:将原纪录删除,新插入纪录,这显然不是期望的处理方式。
  2. 在做客户端API时,有时需要一个默认的图片card,不希望它跳转或作为普通图片可查看大图,只是让它作为默认显示(something like 背景图)
'pic_items' => array(
    '0' => array(
        'pic' => 'http://example.com/pic.jpg',
        'scheme'=>'sinaweibo://javascript:void(0);',
    ),
),

类似浏览器js的写法,scheme为sinaweibo://javascript:void(0);就好了。

堆排序\链表实现局部排序

以前面试时被问一个问题:有10万个乱序的数,要前5个最大(或最小)的数?
作为一个没好好学算法的人,还没有算法时间、空间复杂度的概念,只提出了冒泡、快速排序等,然后取前5。这显然不是合理的做法。

读了几本书,有一点点心得,下面介绍两个做法:
假设:输入为[31,5,12,24,41,63,7,61,42,21,9,123,24...] ,总数为N=100000,要求前M=5个最大的数

  1. 对10万个建立二叉堆,然后应用堆排序5次,即取出前5个最大(或最小)的数。
    只是一个可行的方法,在此不敖述,具体可参见《数据结构与算法分析:C语言描述》、《数据结构(C语言版)》严蔚敏等书中的堆排序。

  2. 考虑:能否维护一个数据结构用来存储排好序的5个数,要求如果输入数大于5个中最小的数,就将其插入至正确位置,并删除最小的数。这样对输入进行一次遍历,即可找出最大的5个数。
    此处想到的是用单链表,首先对输入中前5个数字升序排序,插入空的链表中。

//简单冒泡排序,输入少,对整体性能影响可忽略不计
for(int j=1; j<M; j++){
    for(int k=0; k<M-j; k++){
        if(input[k]>input[k+1]){
            tmp = input[k];
            input[k] = input[k+1];
            input[k+1]=tmp;
        }
    }
}
for(int i=0; i<M; i++){
    Insert(input[i],L,P);//依次插入链表
    P = P->Next;
}

图片 1.png

Position Tmp,TmpCell;
for( ; i<N; i++){ //对其余输入进行一次遍历
    P = Header(L); //表头
    do{
        Tmp = P;//暂存前驱元,保存位置
        P = P->Next;//第一个元素
        if( input[i] <= P->Value ){ //小于第一个元素或者后面的某一个元素
            if(P != L->Next){ //input[i]大小介于第一个元素与此位置的元素
                Insert(in[i],L1,Tmp); //插入
                TmpCell = L1->Next;
                L1->Next = TmpCell->Next;
                free( TmpCell ); //挤出第一个元素,也就是5+1=6个中最小的元素
            }
            break;
        }else if(input[i] > P->Value && IsLast( P, L )){ //如果大于最后一个(也就是最大的)元素
            Insert(in[i],L,P); //插入到最后
            TmpCell = L->Next; L->Next = TmpCell->Next; free(TmpCell); //删除第一个元素(6个中最小的)
            break;
        }
    } while( !IsLast(P, L) );
}

插入可能是这样的:
图片 2.png

删除首元可能是这样的:
图片 3.png

小结:当输入大数据量,而只需前m个最大(最小)值时,应用链表不失为一个好办法,它只对输入进行一次遍历,时间复杂度O(N),空间也只不过额外是一个含6个元素的链表大小而已。
欢迎指教。

PHP的GD库freetype编译安装问题及解决办法

首先说明:

  1. 我的环境是Mac OS X,大家知道mac是基于unix,所以从源代码编译安装三步曲:./configure 、 make 、 make install 是都知晓的。
  2. 编译安装三步曲,是可以无限重复进行的。当然有时你要make clean一下。

在一些带验证码、做水印、一些图片处理的PHP项目中,要用到GD库(从PHP 4.3.0开始,绑定到PHP源代码的ext里),在./configure时,使用 --with-gd安装。通常GD库主要有libpng\libjpeg\freetype2\t1lib这四个依赖,而libpng需要zlib(unix/linux系统都会有这个库,不用自己下载安装)。
libpng\libjpeg\ freetype2 \t1lib 这四个库,就要自己先安装好
三种方式:

  1. 从他们的官网中下载稳定版,从源码安装,安装到/usr/local(./configure --prefix=/usr/local)
  2. yum apt-get等方式安装(我的mac没装这几个命令,所以我没有采用这种方式)
  3. 这个方式仅限Mac:Homebrew ———— The missing package manager for OS X,可去其github看文档,安装后几个简单命令,就把这些依赖的库安装好了,非常方便。

现在,我们已经解决了GD的所有依赖,只要在./configure时加上以下几个配置项:

--with-gd --with-zlib --with-png-dir=/usr/local --with-jpeg-dir=/usr/local --with-freetype-dir=/usr/local --with-t1lib=/usr/local 

再 sudo make 、 sudo make install 就完事了!
gd.png

遇到的一些问题:

  1. Mac是自带PHP的,版本稍旧一点且源码也没有了,不如把自带的干掉,重新编译安装一个(比如PHP 5.5)!系统默认的PHP安装在/usr,我们自己通常安装在/usr/local里。
    彻底删除自带的PHP:
cd /private/etc/
sudo rm -rf php-fpm.conf.default php.ini php.ini.default
cd /usr/bin/
sudo rm -rf php php-config phpdoc phpize
cd /usr/include
sudo rm -rf php
cd /usr/lib
sudo rm -rf php
cd /usr/sbin
sudo rm -rf php-fpm
cd /usr/share
sudo rm -rf php
cd /usr/share/man/man1
sudo rm -rf php-config.1 php.1 phpize.1
cd /usr/share/man/man8
sudo rm -rf php-fpm.8
  1. 因为不断试用关于GD的这几个配置项,我编译安装三步曲起码进行了十多次。你会发现第一次编译安装时间很长,之后重复编译安装很快就完成了,是因为有一些步骤就跳过了。所以改了一些配置项,phpinfo()中的预期的GD的信息却没有。所以重复三步曲前,make clean 进行一下就ok了。

我的配置项:./configure --prefix=/usr/local/php --enable-mbstring --with-apxs2=/usr/sbin/apxs --with-mysql --with-pdo-mysql --enable-zip --with-mysqli --with-curl=/usr/local/opt/curl
说明:
--with-apxs2=/usr/sbin/apxs 这个配置项是针对Apache2.x版本,=[DIR]为apxs命令的位置
--with-curl=/usr/local/opt/curl 详见curl安装