关于面试

好的面试可以将人的缺点暴露无疑,在关于我的页面上,今天加上这条:

curious about everything, but have no patience to insist on one!

CSS Position的使用

前几天微博上一位前端界的大牛吐槽面试的时候问一个position的问题能刷掉一半人,然后引发了一次关于面试和面试题的风波。作为PHPER表示很淡定,但是本PHPER志在成为一个comprehensive and professional web-develop engineer,所以呢,不管前端后端,数据库服务器,我都是想深入搞定的。至于这个position的问题,个人用的不深,但是目前来看平时做布局的时候只要注意absolute和fixed这两个属性即可,absolute如果在父元素没有relative或者absolute的情况想是相对body定位的,否则相对父元素定位,fixed在IE6不能用。这两点至少能解决我目前90%以上的问题了。下面转一博文,基本写到了。

——————————————————————–分割线—————————————————————————————–

CSS的很多其他属性大多容易理解,比如字体,文本,背景等。有些CSS书籍也会对这些简单的属性进行大张旗鼓的介绍,而偏偏忽略了对一些难缠的属性讲解,有避重就轻的嫌疑。CSS中主要难以理解的属性包括盒型结构,以及定位。正如positioniseverything,本文将主要讲述关于position的理解,力求让您看完本文后对position有着最全面的认识。

position的四个属性值:

  1. relative
  2. absolute
  3. fixed
  4. static

下面分别讲述这四个属性。

<div id=”parent”>
<div id=”sub1″>sub1</div>
<div id=”sub2″>sub2</div>
</div>

1. relative

relative属性相对比较简单,我们要搞清它是相对哪个对象来进行偏移的。答案是它本身的位置。在上面的代码中,sub1和sub2是同级关系,如果设定sub1一个relative属性,比如设置如下CSS代码:

#sub1
{
position: relative;
padding: 5px;
top: 5px;
left: 5px;
}

我们可以这样理解,如果不设置relative属性,sub1的位置按照正常的文档流,它应该处于某个位置。但当设置sub1为的position为relative后,将根据top,right,bottom,left的值按照它理应所在的位置进行偏移,relative的“相对的”意思也正体现于此。

对于此,您只需要记住,sub1如果不设置relative时它应该在哪里,一旦设置后就按照它理应在的位置进行偏移。

随后的问题是,sub2的位置又在哪里呢?答案是它原来在哪里,现在就在哪里,它的位置不会因为sub1增加了position的属性而发生改变。

如果此时把sub2的position也设置为relative,会发生什么现象?此时依然和sub1一样,按照它原来应有的位置进行偏移。

注意relative的偏移是基于对象的margin的左上侧的。

2. absolute

这个属性总是有人给出误导。说当position属性设为absolute后,总是按照浏览器窗口来进行定位的,这其实是错误的。实际上,这是fixed属性的特点。

当sub1的position设置为absolute后,其到底以谁为对象进行偏移呢?这里分为两种情况:

(1)当sub1的父对象(或曾祖父,只要是父级对象)parent也设置了position属性,且position的属性值为absolute或者relative时,也就是说,不是默认值的情况,此时sub1按照这个parent来进行定位。

注意,对象虽然确定好了,但有些细节需要您的注意,那就是我们到底以parent的哪个定位点来进行定位呢?如果parent设定了margin,border,padding等属性,那么这个定位点将忽略padding,将会从padding开始的地方(即只从padding的左上角开始)进行定位,这与我们会想当然的以为会以margin的左上端开始定位的想法是不同的。

接下来的问题是,sub2的位置到哪里去了呢?由于当position设置为absolute后,会导致sub1溢出正常的文档流,就像它不属于 parent一样,它漂浮了起来,在DreamWeaver中把它称为“层”,其实意思是一样的。此时sub2将获得sub1的位置,它的文档流不再基于 sub1,而是直接从parent开始。

(2)如果sub1不存在一个有着position属性的父对象,那么那就会以body为定位对象,按照浏览器的窗口进行定位,这个比较容易理解。

3. fixed

fixed是特殊的absolute,即fixed总是以body为定位对象的,按照浏览器的窗口进行定位。

4. static

position的默认值,一般不设置position属性时,会按照正常的文档流进行排列。

 

来源

dropbox客户端实时同步

环境1:

win7, dropbox windows客户端

环境2:

ubunt12.04, dropbox linux客户端

问题描述:

在环境1的dropbox目录某同步文件夹内同步一个文件,在环境2的同一同步文件夹中没有实时文件的更新同步

问题原因:

dropbox文件更新的通知请求被狗日的gfw屏蔽,环境2中的客户端没有收到有更新的通知,自然不会去启动同步

解决办法:

上代理,在prefrence->proxy菜单中修改,改成可以翻墙的代理即可。我这边是走的ssh隧道,用的socket5代理。

开启代理测试后在几秒内就会开始同步了!

Zend Framework Coding Style

绪论

适用范围

本文档提供的代码格式和文档的指南是给参与 Zend Framework 的个人和团队使用的,许多使用 Zend Framework 的开发者 也发现编码标准很有用,因为他们的代码风格和 Zend Framework 的代码保持一致。值得注意的是它要求切实努力来全面 详细说明编码标准。 注:有时候开发者认为在最详细的设计级别上标准的建立比标准所建议的更重要。Zend Framework 编码标准的指南 实践上很好地工作于 ZF 项目。你可以根据我们的 » license 中的条款来修改或使用它们。

ZF 编码标准的话题包括:

  • PHP File 文件格式
  • 命名约定
  • 编码风格
  • 注释文档

目标

编码标准对任何开发项目都很重要,特别是很多开发者在同一项目上工作。编码标准帮助确保代码的高质量、少 bug 和容易维护

 

PHP File 文件格式

常规

对于只包含有 PHP 代码的文件,结束标志(”?>”)是不允许存在的,PHP自身不需要(”?>”), 这样做, 可以防止它的末尾的被意外地注入相应。

重要: 由 __HALT_COMPILER() 允许的任意的二进制代码的内容被 Zend Framework 中的 PHP 文件或由它们产生的文件禁止。 这个功能的使用只对一些安装脚本开放。

缩进

缩进由四个空格组成,禁止使用制表符 TAB 。

行的最大长度

一行 80 字符以内是比较合适,就是说,ZF 的开发者应当努力在可能的情况下保持每行代码少于 80 个字符,在有些情况下,长点也可以, 但最多为 120 个字符。

行结束标志

行结束标志遵循 Unix 文本文件的约定,行必需以单个换行符(LF)结束。换行符在文件中表示为 10,或16进制的 0x0A。

注:不要使用 苹果操作系统的回车(0x0D)或 Windows 电脑的回车换行组合如(0x0D,0x0A)。

 

命名约定

Zend Framework 的类命名总是对应于其所属文件的目录结构的,ZF 标准库的根目录是 “Zend/”,ZF 特别(extras)库的根目录是 “ZendX/”,所有 Zend Framework 的类在其下按等级存放。

类名只允许有字母数字字符,在大部分情况下不鼓励使用数字。下划线只允许做路径分隔符;例如 Zend/Db/Table.php 文件里对应的类名称是 Zend_Db_Table。

如果类名包含多个单词,每个单词的第一个字母必须大写,连续的大写是不允许的,例如 “Zend_PDF” 是不允许的,而 “Zend_Pdf” 是可接受的。

这些约定为 Zend Framework 定义了一个伪命名空间机制。如果对开发者在他们的程序中切实可行,Zend Framework 将采用 PHP 命名空间特性(如果有的话)。

参见在标准和特别库中类名作为类名约定的例子。 重要: 依靠 ZF 库展开的代码,但又不是标准或特别库的一部分(例如程序代码或不是 Zend 发行的库),不要以 “Zend_” 或 “ZendX_” 开头。

文件名

对于其它文件,只有字母数字字符、下划线和短横线(”-“)可用,空格是绝对不允许的。

包含任何 PHP 代码的任何文件应当以 “.php” 扩展名结尾,众所周知的视图脚本除外。下面这些例子给出 Zend Framework 类可接受的文件名:

Zend/Db.php

Zend/Controller/Front.php

Zend/View/Helper/FormRadio.php

文件名必须遵循上述的对应类名的规则。

函数和方法

函数名只包含字母数字字符,下划线是不允许的。数字是允许的但大多数情况下不鼓励。

函数名总是以小写开头,当函数名包含多个单词,每个子的首字母必须大写,这就是所谓的 “驼峰” 格式。

我们一般鼓励使用冗长的名字,函数名应当长到足以说明函数的意图和行为。

这些是可接受的函数名的例子:

filterInput()

getElementById()

widgetFactory()

对于面向对象编程,实例或静态变量的访问器总是以 “get” 或 “set” 为前缀。在设计模式实现方面,如单态模式(singleton)或工厂模式(factory), 方法的名字应当包含模式的名字,这样名字更能描述整个行为。

在对象中的方法,声明为 “private” 或 “protected” 的, 名称的首字符必须是一个单个的下划线,这是唯一的下划线在方法名字中的用法。声明为 “public” 的从不包含下划线。

全局函数 (如:”floating functions”) 允许但大多数情况下不鼓励,建议把这类函数封装到静态类里。

变量

变量只包含数字字母字符,大多数情况下不鼓励使用数字,下划线不接受。

声明为 “private” 或 “protected” 的实例变量名必须以一个单个下划线开头,这是唯一的下划线在程序中的用法,声明为 “public” 的不应当以下划线开头。

对函数名(见上面 3.3 节)一样,变量名总以小写字母开头并遵循“驼峰式”命名约定。

我们一般鼓励使用冗长的名字,这样容易理解代码,开发者知道把数据存到哪里。除非在小循环里,不鼓励使用简洁的名字如 “$i” 和 “$n” 。如果一个循环超过 20 行代码,索引的变量名必须有个具有描述意义的名字。

常量

常量包含数字字母字符和下划线,数字允许作为常量名。

常量名的所有字母必须大写。

常量中的单词必须以下划线分隔,例如可以这样 EMBED_SUPPRESS_EMBED_EXCEPTION 但不许这样 EMBED_SUPPRESSEMBEDEXCEPTION

常量必须通过 “const” 定义为类的成员,强烈不鼓励使用 “define” 定义的全局常量。

 

编码风格

PHP 代码划分(Demarcation)

PHP 代码总是用完整的标准的 PHP 标签定界:

<?php

?>

短标签( )是不允许的,只包含 PHP 代码的文件,不要结束标签 (参见 常规)。

字符串

字符串文字

当字符串是文字(不包含变量),应当用单引号( apostrophe )来括起来:

$a = 'Example String';

包含单引号(’)的字符串文字

当文字字符串包含单引号(apostrophe )就用双引号括起来,特别在 SQL 语句中有用:

$sql = "SELECT `id`, `name` from `people` WHERE `name`='Fred' OR `name`='Susan'";

在转义单引号时,上述语法是首选的,因为很容易阅读。

变量替换

变量替换有下面这些形式:

$greeting = "Hello $name, welcome back!";

$greeting = "Hello {$name}, welcome back!";

为保持一致,这个形式不允许:

$greeting = "Hello ${name}, welcome back!";

字符串连接

字符串必需用 “.” 操作符连接,在它的前后加上空格以提高可读性:

$company = 'Zend' . ' ' . 'Technologies';

当用 “.” 操作符连接字符串,鼓励把代码可以分成多个行,也是为提高可读性。在这些例子中,每个连续的行应当由 whitespace 来填补,例如 “.” 和 “=” 对齐:

$sql = "SELECT `id`, `name` FROM `people` "
     . "WHERE `name` = 'Susan' "
     . "ORDER BY `name` ASC ";

数组

数字索引数组

索引不能为负数

建议数组索引从 0 开始。

当用 array 函数声明有索引的数组,在每个逗号的后面间隔空格以提高可读性:

$sampleArray = array(1, 2, 3, 'Zend', 'Studio');

可以用 “array” 声明多行有索引的数组,在每个连续行的开头要用空格填补对齐:

$sampleArray = array(1, 2, 3, 'Zend', 'Studio',
                     $a, $b, $c,
                     56.44, $d, 500);

关联数组

当用声明关联数组,array 我们鼓励把代码分成多行,在每个连续行的开头用空格填补来对齐键和值:

$sampleArray = array('firstKey'  => 'firstValue',
                     'secondKey' => 'secondValue');

类的声明

用 Zend Framework 的命名约定来命名类。

花括号应当从类名下一行开始(the “one true brace” form)。

每个类必须有一个符合 PHPDocumentor 标准的文档块。

类中所有代码必需用四个空格的缩进。

每个 PHP 文件中只有一个类。

放另外的代码到类里允许但不鼓励。在这样的文件中,用两行空格来分隔类和其它代码。

下面是个可接受的类的例子: // 459 9506 - 441 9658 下次从这里开始

/**
 * Documentation Block Here
 */
class SampleClass
{
    // 类的所有内容
    // 必需缩进四个空格
}

类成员变量

必须用Zend Framework的变量名约定来命名类成员变量。

变量的声明必须在类的顶部,在方法的上方声明。

不允许使用 var (因为 ZF 是基于 PHP 5 的 ),要用 private、 protected 或 public。 直接访问 public 变量是允许的但不鼓励,最好使用访问器 (set/get)。

函数和方法

函数和方法声明

必须用Zend Framework的函数名约定来命名函数。

在类中的函数必须用 private、 protected 或 public 声明它们的可见性。

象类一样,花括号从函数名的下一行开始(the “one true brace” form)。

函数名和括参数的圆括号中间没有空格。

强烈反对使用全局函数。

下面是可接受的在类中的函数声明的例子:

/**
 * Documentation Block Here
 */
class Foo
{
    /**
     * Documentation Block Here
     */
    public function bar()
    {
        // 函数的所有内容
        // 必需缩进四个空格
    }
}

注: 传址(Pass-by-reference)是在方法声明中允许的唯一的参数传递机制。

/**
 * Documentation Block Here
 */
class Foo
{
    /**
     * Documentation Block Here
     */
    public function bar(&$baz)
    {}
}

传址在调用时是严格禁止的。

返回值不能在圆括号中,这妨碍可读性而且如果将来方法被修改成传址方式,代码会有问题。

/**
 * Documentation Block Here
 */
class Foo
{
    /**
     * WRONG
     */
    public function bar()
    {
        return($this->bar);
    }

    /**
     * RIGHT
     */
    public function bar()
    {
        return $this->bar;
    }
}

函数和方法的用法

函数的参数应当用逗号和紧接着的空格分开,下面可接受的调用的例子中的函数带有三个参数:

threeArguments(1, 2, 3);

传址方式在调用的时候是严格禁止的,参见函数的声明一节如何正确使用函数的传址方式。

带有数组参数的函数,函数的调用可包括 “array” 提示并可以分成多行来提高可读性,同时,书写数组的标准仍然适用:

threeArguments(array(1, 2, 3), 2, 3);

threeArguments(array(1, 2, 3, 'Zend', 'Studio',
                     $a, $b, $c,
                     56.44, $d, 500), 2, 3);

控制语句

if/Else/Elseif

使用 if and elseif 的控制语句在条件语句的圆括号前后都必须有一个空格。

在圆括号里的条件语句,操作符必须用空格分开,鼓励使用多重圆括号以提高在复杂的条件中划分逻辑组合。

前花括号必须和条件语句在同一行,后花括号单独在最后一行,其中的内容用四个空格缩进。

if ($a != 2) {
    $a = 2;
}

对包括”elseif” 或 “else”的 “if” 语句,和 “if” 结构的格式类似, 下面的例子示例 “if” 语句, 包括 “elseif” 或 “else” 的格式约定:

if ($a != 2) {
    $a = 2;
} else {
    $a = 7;
}

if ($a != 2) {
    $a = 2;
} elseif ($a == 3) {
    $a = 4;
} else {
    $a = 7;
}

在有些情况下, PHP 允许这些语句不用花括号,但在(ZF) 代码标准里,它们(”if”、 “elseif” 或 “else” 语句)必须使用花括号。”elseif” 是允许的但强烈不鼓励,我们支持 “else if” 组合。

Switch

在 “switch” 结构里的控制语句在条件语句的圆括号前后必须都有一个单个的空格。

“switch” 里的代码必须有四个空格缩进,在”case”里的代码再缩进四个空格。

switch ($numPeople) {
    case 1:
        break;

    case 2:
        break;

    default:
        break;
}

switch 语句应当有 default

注: 有时候,在 falls through 到下个 case 的 case 语句中不写 break or return 很有用。 为了区别于 bug,任何 case 语句中,所有不写break or return 的地方应当有一个 “// break intentionally omitted” 这样的注释来表明 break 是故意忽略的。

注释文档

格式

所有文档块 (“docblocks”) 必须和 phpDocumentor 格式兼容,phpDocumentor 格式的描述超出了本文档的范围,关于它的详情,参考:» http://phpdoc.org/

所有类文件必须在文件的顶部包含文件级 (”file-level”)的 docblock ,在每个类的顶部放置一个 “class-level” 的 docblock。下面是一些例子:

文件

每个包含 PHP 代码的文件必须至少在文件顶部的 docblock 包含这些 phpDocumentor 标签:

/**
 * 文件的简短描述
 *
 * 文件的详细描述(如果有的话)... ...
 *
 * LICENSE: 一些 license 信息
 *
 * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/3_0.txt   BSD License
 * @version    $Id:$
 * @link       http://framework.zend.com/package/PackageName
 * @since      File available since Release 1.5.0
*/

每个类必须至少包含这些 phpDocumentor 标签:

/**
 * 类的简述
 *
 * 类的详细描述 (如果有的话)... ...
 *
 * @copyright  Copyright (c) 2005-2011 Zend Technologies USA Inc. (http://www.zend.com)
 * @license    http://framework.zend.com/license/   BSD License
 * @version    Release: @package_version@
 * @link       http://framework.zend.com/package/PackageName
 * @since      Class available since Release 1.5.0
 * @deprecated Class deprecated in Release 2.0.0
 */

函数

每个函数,包括对象方法,必须有最少包含下列内容的文档块(docblock):

  • 函数的描述
  • 所有参数
  • 所有可能的返回值

因为访问级已经通过 “public”、 “private” 或 “protected” 声明, 不需要使用 “@access”。

如果函数/方法抛出一个异常,使用 @throws 于所有已知的异常类:

@throws exceptionclass [description]

PHP Coding Style

PSR-0

下面描述了关于自动加载器特性强制性要求:

强制性

  • 一个完全标准的命名空间必须要有以下的格式结构\<Vendor Name>\(<Namespace>\)*<Class Name>
  • 命名空间必须有一个顶级的组织名称 (“Vendor Name”).
  • 命名空间中可以根据情况使用任意数量的子空间
  • 从文件系统中加载源文件的时,命名空间中的分隔符将被映射为 DIRECTORY_SEPARATOR
  • 命名空间中的类名中的_没有特殊含义,也将被作为DIRECTORY_SEPARATOR对待.
  • 标准的命名空间和类从文件系统加载源文件时只需要加上.php后缀即可
  • 组织名,空间名,类名都可以随意使用大小写英文字符的组合

示例

  • \Doctrine\Common\IsolatedClassLoader => /path/to/project/lib/vendor/Doctrine/Common/IsolatedClassLoader.php
  • \Symfony\Core\Request => /path/to/project/lib/vendor/Symfony/Core/Request.php
  • \Zend\Acl => /path/to/project/lib/vendor/Zend/Acl.php
  • \Zend\Mail\Message => /path/to/project/lib/vendor/Zend/Mail/Message.php

命名空间和类名中的下划线

  • \namespace\package\Class_Name => /path/to/project/lib/vendor/namespace/package/Class/Name.php
  • \namespace\package_name\Class_Name => /path/to/project/lib/vendor/namespace/package_name/Class/Name.php

以上是我们为轻松实现自动加载特性设定的最低标准。你可以利用下面这个可以自动加载 PHP 5.3 类的SplClassLoader来测试你的代码是否符合以上这些标准。

实例

下面是一个函数实例简单展示如何使用上面建议的标准进行自动加载

<?php

function autoload($className)
{
    $className = ltrim($className, '\\');
    $fileName  = '';
    $namespace = '';
    if ($lastNsPos = strrpos($className, '\\')) {
        $namespace = substr($className, 0, $lastNsPos);
        $className = substr($className, $lastNsPos + 1);
        $fileName  = str_replace('\\', DIRECTORY_SEPARATOR, $namespace) . DIRECTORY_SEPARATOR;
    }
    $fileName .= str_replace('_', DIRECTORY_SEPARATOR, $className) . '.php';

    require $fileName;
}

SplClassLoader实现

下面的gist是一个可以按照上面建议的自动加载特性来加载类的SplClassLoader实例。这也是我们当前在PHP5.3中依据以上标准加载类时推荐的方。

 

PSR-1

基本代码规范

本节标准包含了成为标准代码所需要的基本元素,以确保开源出来的PHP代码之间有较高度的技术互用性。

在 RFC 2119中的特性关键词”必须”(MUST),“不可”(MUST NOT),“必要”(REQUIRED),“将会”(SHALL),“不会”(SHALL NOT),“应当”(SHOULD),“不应”(SHOULD NOT),“推荐”(RECOMMENDED),“可以”(MAY)和“可选”(OPTIONAL)在这文档中将被用来描述。

1. 大纲

  • 源文件必须只使用 <?php 和 <?= 标签。
  • 源文件中必须只使用不带BOM的UTF-8作为PHP代码。
  • 源文件应当只声明符号(类,函数,常量等…)或者引起副作用(例如:生成输出,修改.ini配置等),但不应同时做这两件事。
  • 命名空间和类必须遵守 PSR-0
  • 类名必须使用骆驼式StudlyCaps写法 (译者注:驼峰式的一种变种,后文将直接用StudlyCaps表示)。
  • 类中的常量必须使用全大写和下划线分隔符。
  • 方法名必须使用驼峰式cameCase写法(译者注:后文将直接用camelCase表示)。

2. 文件

2.1. PHP标签

PHP代码必须只使用长标签<?php ?>或者短输出式<?= ?>标签;它不可使用其他的标签变种。

2.2. 字符编码

PHP代码必须只使用不带BOM的UTF-8。

2.3. 副作用

一个文件应当声明新符号 (类名,函数名,常量等)并且不产生副作用,或者应当执行有副作用的逻辑,但不能同时做这两件事。

短语”副作用”意思是不直接执行逻辑的类,函数,常量等 仅包括文件

“副作用”包含但不局限于:生成输出,显式地使用requireinclude,连接外部服务,修改ini配置,触发错误或异常,修改全局或者静态变量,读取或修改文件等等

下面是一个既包含声明又有副作用的示例文件;即应避免的例子:

<?php
// side effect: change ini settings
ini_set('error_reporting', E_ALL);

// side effect: loads a file
include "file.php";

// side effect: generates output
echo "<html>\n";

// declaration
function foo()
{
    // function body
}

下面是一个仅包含声明的示例文件;即需要提倡的例子:

<?php
// declaration
function foo()
{
    // function body
}

// conditional declaration is *not* a side effect
if (! function_exists('bar')) {
    function bar()
    {
        // function body
    }
}

3. 命名空间和类名

命名空间和类名必须遵守 PSR-0.

这意味着每个类必须单独一个源文件,并且至少有一级命名空间:顶级的组织名。

类名必须使用骆驼式StudlyCaps写法。

PHP5.3之后的代码必须使用正式的命名空间 例子:

<?php
// PHP 5.3 and later:
namespace Vendor\Model;

class Foo
{
}

PHP5.2.x之前的代码应当用伪命名空间Vendor_作为类名的前缀

<?php
// PHP 5.2.x and earlier:
class Vendor_Model_Foo
{
}

4. 类常量,属性和方法

术语“类”指所有的类,接口和特性(traits)

4.1. 常量

类常量必须使用全大写,并使用分隔符作为下划线。 例子:

<?php
namespace Vendor\Model;

class Foo
{
    const VERSION = '1.0';
    const DATE_APPROVED = '2012-06-01';
}

4.2. 属性

本手册有意避免推荐使用$StulyCaps$camelCase或者unser_score作为属性名字

不管名称如何约定,它应当在一个合理范围内保持一致。这个范围可能是组织层,包层,类层,方法层。

4.3. 方法

方法名必须用camelCase()写法。

 

PSR-2

代码样式规范

本手册是 PSR-1基础代码规范的继承和扩展

本指南的意图是为了减少不同开发者在浏览代码时减少认知的差异。 为此列举一组如何格式化PHP代码的共用规则。

各个成员项目的共性组成了本文的样式规则。当不同的开发者在不同的项目中合作时,将会在这些不同的项目中使用一个共同的标准。 因此,本指南的好处不在于规则本身,而在于共用这些规则。

在 RFC 2119中的特性关键词”必须”(MUST),“不可”(MUST NOT),“必要”(REQUIRED),“将会”(SHALL),“不会”(SHALL NOT),“应当”(SHOULD),“不应”(SHOULD NOT),“推荐”(RECOMMENDED),“可以”(MAY)和“可选”(OPTIONAL)在这文档中将被用来描述。

1. 大纲

  • 代码必须遵守 PSR-1
  • 代码必须使用4个空格的缩进,而不是制表符。
  • 一行代码长度不应硬性限制;软限制必须为120个字符;也应当是80个字符或者更少。
  • namespace声明下面必须有一个空行,并且use声明代码块下面也必须有一个空行。
  • 类的左花括号必须放到下一行,右花括号必须放在类主体的下一行。
  • 方法的左花括号必须放在下一行,右花括号必须放在方法主体下面。
  • 所有的属性和方法必须有可见性(译者注:Public, Protect, Private)声明;abstractfinal声明必须在可见性之前;static声明必须在可见性之后。
  • 控制结构的关键词必须在后面有一个空格; 方法和函数不可有。
  • 控制结构的左花括号必须放在同一行,右花括号必须放在控制主体的下一行。
  • 控制结构的左括号后面不可有空格,右括号之前不可有空格。

1.1. 示例

本示例包含上面的一些规则简单展示:

<?php
namespace Vendor\Package;

use FooInterface;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class Foo extends Bar implements FooInterface
{
    public function sampleFunction($a, $b = null)
    {
        if ($a === $b) {
            bar();
        } elseif ($a > $b) {
            $foo->bar($arg1);
        } else {
            BazClass::bar($arg2, $arg3);
        }
    }

    final public static function bar()
    {
        // method body
    }
}

2. 概括

2.1 基础代码规范

代码必须遵守 PSR-1 的所有规则。

2.2 文件

所有的PHP文件必须使用Unix LF(换行)作为行结束符。

所有PHP文件必须以一个空行结束。

纯PHP代码的文件关闭标签?>必须省略

2.3. 行

行长度不可有硬限制。

行长度的软限制必须是120个字符;对于软限制,自动样式检查器必须警告但不可报错。

行实际长度不应超过80个字符;较长的行应当被拆分成多个不超过80个字符的后续行。

在非空行后面不可有空格。

空行可以用来改善可读性和区分相关的代码块。

一行不应多于一个语句。

2.4. 缩进

代码必须使用4个空格的缩进,并且不可使用制表符作为缩进。

注意:只用空格,不和制表符混合使用,将会对避免代码差异,补丁,历史和注解中的一些问题有帮助。使用空格还可以使调整细微的缩进来改进行间对齐变得非常简单。

2.5. 关键词和 True/False/Null

PHP keywords 必须使用小写。

PHP常量truefalsenull必须使用小写。

3. Namespace和Use声明

如果存在,namespace声明之后必须有一个空行。

如果存在,所有的use声明必须放在namespace声明的下面。

一个use关键字必须只用于一个声明。

use声明代码块后面必须有一个空行。

示例:

<?php
namespace Vendor\Package;

use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

// ... additional PHP code ...

4. 类,属性和方法

术语“类”指所有的类,接口和特性(traits)。

4.1. 扩展和继承

一个类的extendsimplements关键词必须和类名在同一行。

类的左花括号必须放在下面自成一行;右花括号必须放在类主体的后面自成一行。

<?php
namespace Vendor\Package;

use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class ClassName extends ParentClass implements \ArrayAccess, \Countable
{
    // constants, properties, methods
}

implements一个列表可以被拆分为多个有一次缩进的后续行。如果这么做,列表的第一项必须要放在下一行,并且每行必须只有一个接口。

<?php
namespace Vendor\Package;

use FooClass;
use BarClass as Bar;
use OtherVendor\OtherPackage\BazClass;

class ClassName extends ParentClass implements
    \ArrayAccess,
    \Countable,
    \Serializable
{
    // constants, properties, methods
}

4.2. 属性

所有的属性必须声明可见性。

var关键词不可用来声明属性。

一个语句不可声明多个属性。

属性名称不应使用单个下划线作为前缀来表明保护或私有的可见性。

一个属性声明看起来应该下面这样的。

<?php
namespace Vendor\Package;

class ClassName
{
    public $foo = null;
}

4.3. 方法

所有的方法必须声明可见性。

方法名不应只使用单个下划线来表明是保护或私有的可见性。

方法名在声明之后不可跟随一个空格。左花括号必须放在下面自成一行,并且右花括号必须放在方法主体的下面自成一行。左括号后面不可有空格,右括号前面不可有空格。

一个方法定义看来应该像下面这样。 注意括号,逗号,空格和花括号:

<?php
namespace Vendor\Package;

class ClassName
{
    public function fooBarBaz($arg1, &$arg2, $arg3 = [])
    {
        // method body
    }
}

4.4. 方法参数

在参数列表中,逗号之前不可有空格,逗号之后必须要有一个空格。

方法中有默认值的参数必须放在参数列表的最后面。

<?php
namespace Vendor\Package;

class ClassName
{
    public function foo($arg1, &$arg2, $arg3 = [])
    {
        // method body
    }
}

参数列表可以被分为多个有一次缩进的多个后续行。如果这么做,列表的第一项必须放在下一行,并且每行必须只放一个参数。

当参数列表被分为多行,右括号和左花括号必须夹带一个空格放在一起自成一行。

<?php
namespace Vendor\Package;

class ClassName
{
    public function aVeryLongMethodName(
        ClassTypeHint $arg1,
        &$arg2,
        array $arg3 = []
    ) {
        // method body
    }
}

4.5. abstractfinal和 static

如果存在,abstractfinal声明必须放在可见性声明前面。

如果存在,static声明必须跟着可见性声明。

<?php
namespace Vendor\Package;

abstract class ClassName
{
    protected static $foo;

    abstract protected function zim();

    final public static function bar()
    {
        // method body
    }
}

4.6. 调用方法和函数

要调用一个方法或函数,在方法或者函数名和左括号之间不可有空格,左括号之后不可有空格,右括号之前不可有空格。函数列表中,逗号之前不可有空格,逗号之后必须有一个空格。

<?php
bar();
$foo->bar($arg1);
Foo::bar($arg2, $arg3);

参数列表可以被拆分成多个有一个缩进的后续行。如果这么做,列表中的第一项必须放在下一行,并且每一行必须只有一个参数。

<?php
$foo->bar(
    $longArgument,
    $longerArgument,
    $muchLongerArgument
);

5. 控制结构

对于控制结构的样式规则概括如下:

  • 控制结构关键词之后必须有一个空格
  • 左括号之后不可有空格
  • 右括号之前不可有空格
  • 在右括号和左花括号之间必须有一个空格
  • 代码主体必须有一次缩进
  • 右花括号必须主体的下一行

每个结构的主体必须被括在花括号里。这结构看上去更标准化,并且当加新行的时候可以减少引入错误的可能性。

5.1. ifelseifelse

一个if结构看起来应该像下面这样。注意括号,空格,花括号的位置;并且elseelseif和前一个主体的右花括号在同一行。

<?php
if ($expr1) {
    // if body
} elseif ($expr2) {
    // elseif body
} else {
    // else body;
}

关键词elseif应该替代else if使用以保持所有的控制关键词像一个单词。

5.2. switchcase

一个switch结构看起来应该像下面这样。注意括号,空格和花括号。case语句必须从switch处缩进,并且break关键字(或其他中止关键字)必须case主体缩进在同级。如果一个非空的case主体往下落空则必须有一个类似// no break的注释。

<?php
switch ($expr) {
    case 0:
        echo 'First case, with a break';
        break;
    case 1:
        echo 'Second case, which falls through';
        // no break
    case 2:
    case 3:
    case 4:
        echo 'Third case, return instead of break';
        return;
    default:
        echo 'Default case';
        break;
}

5.3. whiledo while

一个while语句看起来应该像下面这样。注意括号,空格和花括号的位置。

<?php
while ($expr) {
    // structure body
}

同样的,一个do while语句看起来应该像下面这样。注意括号,空格和花括号的位置。

<?php
do {
    // structure body;
} while ($expr);

5.4. for

一个for语句看起来应该像下面这样。注意括号,空格和花括号的位置。

<?php
for ($i = 0; $i < 10; $i++) {
    // for body
}

5.5. foreach

一个foreach语句看起来应该像下面这样。注意括号,空格和花括号的位置。

<?php
foreach ($iterable as $key => $value) {
    // foreach body
}

5.6. trycatch

一个try catch语句看起来应该像下面这样。注意括号,空格和花括号的位置。

<?php
try {
    // try body
} catch (FirstExceptionType $e) {
    // catch body
} catch (OtherExceptionType $e) {
    // catch body
}

6. 闭包

闭包在声明时function关键词之后必须有一个空格,并且use之前也需要一个空格。

左花括号必须在同一行,右花括号必须在主体的下一行。

参数列表和变量列表的左括号之后不可有空格,其右括号之前也不可有空格。

在参数列表和变量列表中,逗号之前不可有空格,逗号之后必须有空格。

闭包带默认值的参数必须放在参数列表后面。

一个闭包声明看起来应该像下面这样。注意括号,空格和花括号的位置。

<?php
$closureWithArgs = function ($arg1, $arg2) {
    // body
};

$closureWithArgsAndVars = function ($arg1, $arg2) use ($var1, $var2) {
    // body
};

参数和变量列表可以被分成多个带一次缩进的后续行。如果这么做,列表的第一项必须放在下一行,并且一行必须只放一个参数或变量。

当最终列表(不管是参数还是变量)被分成多行,右括号和左花括号必须夹带一个空格放在一起自成一行。

下面是一个参数和变量列表被分割成多行的示例。

<?php
$longArgs_noVars = function (
    $longArgument,
    $longerArgument,
    $muchLongerArgument
) {
   // body
};

$noArgs_longVars = function () use (
    $longVar1,
    $longerVar2,
    $muchLongerVar3
) {
   // body
};

$longArgs_longVars = function (
    $longArgument,
    $longerArgument,
    $muchLongerArgument
) use (
    $longVar1,
    $longerVar2,
    $muchLongerVar3
) {
   // body
};

$longArgs_shortVars = function (
    $longArgument,
    $longerArgument,
    $muchLongerArgument
) use ($var1) {
   // body
};

$shortArgs_longVars = function ($arg) use (
    $longVar1,
    $longerVar2,
    $muchLongerVar3
) {
   // body
};

注意如果在函数或者方法中把闭包作为一个参数调用,如上格式规则同样适用。

<?php
$foo->bar(
    $arg1,
    function ($arg2) use ($var1) {
        // body
    },
    $arg3
);

7. 结论

在该指南中有很多风格的元素和做法有意被忽略掉。这些包括但不局限于:

  • 全局变量和全局常量的声明
  • 方法声明
  • 操作符和赋值
  • 行间对齐
  • 注释和文档块
  • 类名给你前缀和后缀
  • 最佳实践

以后的建议可以修改和扩展该指南以满足这些或其他风格的元素和实践。

 

PSR-3

日志接口

本文档用来描述日志类库的通用接口。

主要目标是让类库获得一个Psr\Log\LoggerInterface对象并且使用一个简单通用的方式来写日志。有自定义需求的框架和CMS可以根据情况扩展这个接口,但应当保持和该文档的兼容性,这将确保使用第三方库和应用能统一的写应用日志。

The key words “MUST”, “MUST NOT”, “REQUIRED”, “SHALL”, “SHALL NOT”, “SHOULD”, “SHOULD NOT”, “RECOMMENDED”, “MAY”, and “OPTIONAL” in this document are to be interpreted as described in RFC 2119.

关键词实现者在这个文档被解释为:在日志相关的库和框架实现LoggerInterface接口的人。用这些实现的人都被称作用户

1. 规范

1.1 基础

  • LoggerInterface暴露八个接口用来记录八个等级(debug, info, notice, warning, error, critical, alert, emergency)的日志。
  • 第九个方法是log,接受日志等级作为第一个参数。用一个日志等级常量来调用这个方法的结果必须和调用具体等级方法的一致。如果具体的实现不知道传入的不按规范的等级来调用这个方法必须抛出一个Psr\Log\InvalidArgumentException。用户不应自定义一个当前不支持的未知等级。

1.2 消息

  • 每个方法都接受字符串,或者有__toString方法的对象作为消息。实现者可以对传入的对象有特殊的处理。如果不是,实现者必须将它转换成字符串。
  • 消息可以包含可以被上下文数组的数值替换的占位符。

    占位符名字必须和上下文数组键名对应。

    占位符名字必须使用使用一对花括号为分隔。在占位符和分隔符之间不能有任何空格。

    占位符名字应该A-Za-z0-9,下划线_和句号.。其它的字符作为以后占位符规范的保留。

    实现者可以使用占位符来实现不同的转义和翻译日志成文。用户在不知道上下文数据是什么的时候不应提前转义占位符。

    下面提供一个占位符替换的例子,仅作为参考:

    /**
    * Interpolates context values into the message placeholders.
    */
    function interpolate($message, array $context = array())
    {
      // build a replacement array with braces around the context keys
      $replace = array();
      foreach ($context as $key => $val) {
          $replace['{' . $key . '}'] = $val;
      }
    
      // interpolate replacement values into the message and return
      return strtr($message, $replace);
    }
    
    // a message with brace-delimited placeholder names
    $message = "User {username} created";
    
    // a context array of placeholder names => replacement values
    $context = array('username' => 'bolivar');
    
    // echoes "Username bolivar created"
    echo interpolate($message, $context);

1.3 上下文

  • 每个方法接受一个数组作为上下文数据,用来存储不适合在字符串中填充的信息。数组可以包括任何东西。实现者必须确保他们对上下文数据足够的掌控。在上下文中一个给定值不可抛出一个异常,也不可产生任何PHP错误,警告或者提醒。
  • 如果在上下文中传入了一个异常对象,它必须以exception作为键名。记录异常轨迹是通用的模式,如果日志底层支持这样也是可以被允许的。实现者在使用它之前必须验证exception的键值是不是一个异常对象,因为它可以允许是任何东西。

1.4 助手类和接口

  • Psr\Log\AbstractLogger类让你非常简单的实现和扩展LoggerInterface接口以实现通用的log方法。其他八个方法将会把消息和上下文转发给它。
  • 类似的,使用Psr\Log\LoggerTrait只需要你实现通用的log方法。记住traits不能实现接口前,你依然需要implement LoggerInterface
  • Psr\Log\NullLogger是和接口一个提供的。它可以为使用接口的用户提供一个后备的“黑洞”。如果上下文数据非常重要,这不失为一个记录日志更好的办法。
  • Psr\Log\LoggerAwareInterface只有一个setLogger(LoggerInterface $logger)方法可以用来随意设置一个日志记录器。
  • Psr\Log\LoggerAwareTraittrait可以更简单的实现等价于接口。通过它可以访问到$this->logger
  • Psr\Log\LogLevel类拥有八个等级的常量。

2. 包

作为psr/log 的一部分,提供接口和相关异常类的一些描述以及一些测试单元用来验证你的实现。

3. Psr\Log\LoggerInterface

<?php

namespace Psr\Log;

/**
 * Describes a logger instance
 *
 * The message MUST be a string or object implementing __toString().
 *
 * The message MAY contain placeholders in the form: {foo} where foo
 * will be replaced by the context data in key "foo".
 *
 * The context array can contain arbitrary data, the only assumption that
 * can be made by implementors is that if an Exception instance is given
 * to produce a stack trace, it MUST be in a key named "exception".
 *
 * See https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-3-logger-interface.md
 * for the full interface specification.
 */
interface LoggerInterface
{
    /**
     * System is unusable.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function emergency($message, array $context = array());

    /**
     * Action must be taken immediately.
     *
     * Example: Entire website down, database unavailable, etc. This should
     * trigger the SMS alerts and wake you up.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function alert($message, array $context = array());

    /**
     * Critical conditions.
     *
     * Example: Application component unavailable, unexpected exception.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function critical($message, array $context = array());

    /**
     * Runtime errors that do not require immediate action but should typically
     * be logged and monitored.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function error($message, array $context = array());

    /**
     * Exceptional occurrences that are not errors.
     *
     * Example: Use of deprecated APIs, poor use of an API, undesirable things
     * that are not necessarily wrong.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function warning($message, array $context = array());

    /**
     * Normal but significant events.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function notice($message, array $context = array());

    /**
     * Interesting events.
     *
     * Example: User logs in, SQL logs.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function info($message, array $context = array());

    /**
     * Detailed debug information.
     *
     * @param string $message
     * @param array $context
     * @return null
     */
    public function debug($message, array $context = array());

    /**
     * Logs with an arbitrary level.
     *
     * @param mixed $level
     * @param string $message
     * @param array $context
     * @return null
     */
    public function log($level, $message, array $context = array());
}

4. Psr\Log\LoggerAwareInterface

<?php

namespace Psr\Log;

/**
 * Describes a logger-aware instance
 */
interface LoggerAwareInterface
{
    /**
     * Sets a logger instance on the object
     *
     * @param LoggerInterface $logger
     * @return null
     */
    public function setLogger(LoggerInterface $logger);
}

5. Psr\Log\LogLevel

<?php

namespace Psr\Log;

/**
 * Describes log levels
 */
class LogLevel
{
    const EMERGENCY = 'emergency';
    const ALERT     = 'alert';
    const CRITICAL  = 'critical';
    const ERROR     = 'error';
    const WARNING   = 'warning';
    const NOTICE    = 'notice';
    const INFO      = 'info';
    const DEBUG     = 'debug';
}

参考1  参考2

基于curl封装一个爬虫

<?php  
if ( ! defined('BASEPATH')) exit('No direct script access allowed');
/**
 * CodeIgniter
 *
 * An open source application development framework for PHP 5.1.6 or newer
 *
 * @package		CodeIgniter
 * @author		ExpressionEngine Dev Team
 * @copyright	Copyright (c) 2008 - 2011, EllisLab, Inc.
 * @license		http://codeigniter.com/user_guide/license.html
 * @link		http://codeigniter.com
 * @since		Version 1.0
 * @filesource
 */

// ------------------------------------------------------------------------

class Crawler {
	private $_url;
	private $_handle;
	//多线程处理时一些变量
	private $_batch_config = array(
											'handle_array' => array(),
											'map_array' => array()
									);
	private $_curl_option;
	private $_single_or_multi = TRUE; //TRUE表示是单个curl句柄,FALSE表示一组批处理curl句柄(多线程操作)

	function __construct() {
		$this->_curl_option = array(
				CURLOPT_TIMEOUT => 60,
				CURLOPT_FOLLOWLOCATION => TRUE,
				CURLOPT_RETURNTRANSFER => TRUE,
				CURLOPT_HEADER => TRUE,
				CURLOPT_NOSIGNAL => TRUE,
		);
	}

	public function deal($url) {
		$this->set_url($url);
		$this->init_handle();

		return $this->get_response();
	}

	public function set_url($url) {
		$this->_url = $url;
		$this->_single_or_multi = is_array($url) ? FALSE : TRUE;
	}

	public function set_curl_option($option) {
		$this->_curl_option = $option;
	}

	public function init_handle() {
		if(is_array($this->_url)) {
			$this->_handle = curl_multi_init();
			foreach ($this->_url as $id=>$s_url) {
				$ch = curl_init($s_url);
				$this->_batch_config['handle_array'][] = $ch;
				curl_setopt_array($ch, $this->_curl_option);

				curl_multi_add_handle($this->_handle, $ch);
				$this->_batch_config['map_array'][(string)$ch] = $id;
// 				print_r($ch);
// 				echo "\n" . (string)$ch . "\n";
			}
			print_r($this->_batch_config);
		}
		else {
			$this->_handle = curl_init($this->_url);
			curl_setopt_array($this->_handle, $this->_curl_option);
		}
	}

	public function get_response() {
		if($this->_single_or_multi) {
			$response = curl_exec($this->_handle);
			curl_close($this->_handle);

			return $response;
		}
		else {
			$responses = array();
			do
			{
				while(($code = curl_multi_exec($this->_handle , $active)) == CURLM_CALL_MULTI_PERFORM);
				if($code != CURLM_OK)
				{
					break;
				}

				// a request was just completed -- find out which one
				while($done = curl_multi_info_read($this->_handle))
				{

					// get the info and content returned on the request
					$content = curl_multi_getcontent($done['handle']);
					$responses[$this->_batch_config['map_array'][(string) $done['handle']]] = $content;//$this->parseHead($content);

					// remove the curl handle that just completed
					curl_multi_remove_handle($this->_handle , $done['handle']);
					curl_close($done['handle']);
				}

				// Block for data in / output; error handling is done by
				// curl_multi_exec
				if($active > 0)
				{
					curl_multi_select($this->_handle , 0.5);
				}
			}
			while($active);

			return $responses;
		}
	}
}

今天在CI下写一个爬虫库,此爬虫支持单url抓取和多线程批量url抓取,以及自定义正则匹配所需要的内容。

未完成

===========2013.05.06============

完成多线程部分,类代码待完善

Apache虚拟主机中NameVirtualHost指令

说明 为一个基于域名的虚拟主机指定一个IP地址(和端口)
语法 NameVirtualHost addr[:port]
作用域 server config
状态 核心(C)
模块 core

如果您要配置基于域名的虚拟主机,NameVirtualHost指令就是您必须的指令之一。

尽管addr参数可以使用主机名,但建议您还是使用IP地址。比如:

NameVirtualHost 111.22.33.44

使用NameVirtualHost指令,您可以指定一个基于域名的虚拟主机将使用哪个IP地址来接受请求。在一个防火墙或是其它代理接受了请求并把它转到服务器所在的另外一个IP地址上的情况下,您必须指定伺服请求的机器物理界面上的IP地址。如果您对于多个地址使用了多个基于域名的虚拟主机,您应该为每个地址使用这个指令。

注意

“主服务器”和任何其它”_default_“服务器都不会伺服发送到NameVirtualHost IP地址的请求。(除非您指定了NameVirtualHost,但没有为这个地址指定任何VirtualHost)。

另外,您还可以为您使用的基于域名的虚拟主机指定一个端口号。比如:

NameVirtualHost 111.22.33.44:8080

IPv6地址必须封装在一对方括号内,如下例所示:

NameVirtualHost [2001:db8::a00:20ff:fea7:ccea]:8080

为了接受所有界面的请求,您可以使用”*“:

NameVirtualHost *

<VirtualHost>指令的参数

请注意,<VirtualHost>指令的参数必须与NameVirtualHost指令的参数完全匹配。

NameVirtualHost 1.2.3.4
<VirtualHost 1.2.3.4>
# ...
</VirtualHost>

[来源]

ubuntu和centos下关于lamp的一些常规操作

本文中centos环境是在root账户下操作的

安装Apache, MySQL, PHP

sudo apt-get install apache2 mysql-server-5.0 php5 libapache2-mod-php5 php5-mysql ...(需要别的模块自己添加)
yum -y install httpd php mysql mysql-server php-mysql httpd-manual mod_ssl mod_perl mod_auth_mysql php-mcrypt php-gd php-xml php-mbstring php-ldap php-pear php-xmlrpc mysql-connector-odbc mysql-devel libdbi-dbd-mysql...(相关模块自己取舍,需要再加)

重启apache服务(其他服务类似)

sudo /etc/init.d/apache2 restart(或sudo service apache2 restart)
/etc/init.d/httpd restart(或 service httpd restart)

Apache相关配置

路径:

/etc/apache2/apache2.conf
/etc/httpd/conf/httpd.conf

虚拟主机配置

可以直接写到上述配置文件中,也可以单独写,我在centos中是直接写到apache主配置文件的,在ubuntu中,配置文件同路径中有两个文件夹,分别是

sites-available和sites-enabled,具体作用不言而喻(同目录中的mods-available和mods-enable文件夹也类似)

在sites-available中配好相关虚拟主机,我一般单独文件一个主机,然后运行

sudo a2ensite 虚拟主机配置文件名

然后restart或者reload apache服务都可以使配置生效。

用户和组

centos下一般是apache:apache

ubuntu下一般是www-data:www-data

Ubuntu 12.04下新建快捷方式

[Desktop Entry]
Name=ZendStudio
Exec=/usr/local/ZendStudio/ZendStudio
Icon=/usr/local/ZendStudio/icon.xpm
Terminal=false
StartupNotify=true
Type=Application
Categories=Development;

把程序包放在/usr/local下面

[转]成本最低的Elance提现方式 — Moneybookers

By Weiny Elance讨论组(162095216)

天朝的人们,看过《Elance 提现那点破事》或者你还是觉得不满Elance 25刀的提现手续费,以及可能潜在的不知名中间行手续费,这里可能有你想要的答案。经过我们Elance讨论组的探索,我们发现Skrill(Moneybookers)给了我们一些惊喜
——每笔提现只需要2.33刀手续费!没错,是一共2.33刀!

如果你感兴趣,不妨加入我们QQ讨论群Elance讨论组(162095216)。——Elance 讨论组,

总有一组人和你一样。

031813_1157_Elance1

问题的起源

以Elance 国际电汇方式提现美刀,Elance 收取25刀/笔的手续费(每月第一次,第二次以上5刀)。但由于Elance 和
中行没有合作关系,所以Elance通过中间行给中行打款。因此中间行也会扣一定的手续费,这使得每月提现的屌丝们每次都需要付40刀左右的手续费。从USD提现到天朝币到手,转换率大概是6.0到6.1左右(算上手续费)。

 

更好的方式

因为由Elance提现到Moneybookers(MB)并不需要手续费。而从MB提现回国内中行只需要1.8EUR 约2.33$-2.34$。而且MB向中行电汇并不涉及中间行费用。这样大大降低了提现的费用成本。下图是MB官网关于费用的说明。

031813_1157_Elance2

MB fee

注册MB

打开这个连接可以看到MB注册页面。选择个人账户后进入个人的详细信息填写页面。注册过程并不复杂,而且MB支持中文,需要的时候可以在页面的右上角找到五星旗切换语言。须要注意的是填写地址的时候须要填写真实可达的地址。MB在后边需要对邮寄地址做认证。如这里的地址填写不精确,后边可以改,不过MB有90天内允许1次地址改动的规定。为避免不必要的麻烦,请填写真实可达的地址。

031813_1157_Elance3

电子邮箱也是个人信息的其中一项。注册提交后MB会发激活链接都该邮箱地址,请保证电子邮箱可达而且你有权限打开。

依照MB的指引完成注册,稍等一会打开注册的邮箱就能看到邮箱验证邮件,依照指引完成邮箱激活。这个并不困难,智商过90应该能处理好。

 

031813_1157_Elance4

邮箱验证邮件内容剪辑

绑定MB账户到Elance

登录Elance,一次进入MANAGE->Financial Accounts,在页面上找到Skrill Account 部分(Skrill是MB的新名字),点击 “Enter New Skrill Account“进入添加页面。输入MB注册邮箱依照指引完成账号添加,并不难。智商过90应该没有问题。

 

031813_1157_Elance5

Elance 需要大概1个工作日完成绑定。这样我们有足够的时间回到MB完成银行卡的绑定以及其他的验证。

 

MB信用卡绑定以及姓名验证

登录MB账号,点击左边栏菜单“View Limit” 则可以看到当前允许操作的金额上限。一个新注册的MB用户,这些上限大概是

  • 对外交易每90天限额,包括提现和付款 ($68.12)
  • 每60天期信用卡/储蓄卡充值限额 ($0.00)
  • 单次交易限额($1382.50)

 

031813_1157_Elance6

限额列表的下方提示了一些可以增加限额的方式。包括信用卡验证,可以提升$3406.25(2500欧)的对外交易限额;银行账户验证,也可以提升另外的2500欧元限额。鉴于银行账户的验证需要到当地银行汇款,手续和费用都比较高,如果非到必要,可以先搁置。本文也不会谈及。信用卡验证也能提高信用卡/借记卡充值上限,这也不在提现所关注的范围。

选择信用卡/借记卡验证方式开始验证信用卡。新打开的页面会收集信用卡信息,依照指引依次填写然后提交。

 

031813_1157_Elance7

在信用卡验证的过程中,MB会从信用卡中随机扣除$1.01 – $2.99。提交验证后一般几分钟内就扣除。扣除后你需要需要从具体信用卡银行中知道准确的扣除金额。这个金额可能从银行给你发的通知短信中查得,或者是登录你的信用卡银行查阅。

 

031813_1157_Elance8

登录MB,点击“Credit/debit card” 旁边的“Verify”连接,然后填入具体扣除的金额,确认,即可完成验证。

在完成验证之后MB从信用卡中扣除的金额会充入你的MB账户,在账户信息首页应该能看到余额的增加。

重新查阅 “View Limit”,这个时候能看到上限已经增加了。

031813_1157_Elance9

地址验证

没有通过地址验证的屌丝们是无法从MB中提现的!切记!

MB的“View Limit”中并没有提到地址验证这桩事,但是当你以为一切都顺利准备从MB中提现的时候,地址验证就会拦在门口要你把钱放下。好狗不拦路,必须清除。

登录MB之后,点左边导航“Summary”标签,在打开页面中找到“Address”一栏,点击右边的“Verify”链接开始验证。

 

031813_1157_Elance10

新打开的页面显示之前注册时候的地址,该地址是只读的。如果地址不正确可以修改,不过注意MB规定每90天只允许修改地址一次。上图所示地址为反面教材,地址并不详细。提交地址验证之后,MB会通过邮递发送一份平邮,这份平邮只允许发送一次,无法重发。所以选择一个确保能收到信件的地址很重要。信件里边有一个6位数字的验证码。拿到该数字后重新以刚才的方式打开地址验证页面就能看到验证码的输入框。输入验证码确认则能通过验证。这是最快最简单的方式。下图是由MB发送的平邮的实物图,名字已经略去。

 

031813_1157_Elance11

通常顺利,10天内能收到MB的信件并完成验证。可是天朝的平邮是个硬伤,我并没有收到他们所说的验证码。这个时候可以向MB提一个ticket,告诉他们邮件可能寄送失败了,要求他们提供另外的验证方式。提ticket可以依次点击 “Email support” ->”My profile” -> “Post Address Verification” -> “
I have a general question about post address verification” 来打开输入框。在文本框中键入你的情况,提交。

MB的客服一般处理很快,当天就能收到反馈,所以注意查收邮箱。以下是我收到客服的邮件内容。客服名字我隐藏了。

 Dear Mr. zhao,

 Thank you for contacting Skrill Customer Service.

 Please be kindly informed that post address verification is a one-time procedure and the verification letter can be sent only once.

 However, we can offer you manual address verification as an alternative. For this purpose we kindly ask you to provide us with a high-resolution scanned copy of a valid address verification document – an address registration certificate, a paper bank statement or any utility bill. The document should:

  •  – Clearly show your names and address (matching the ones registered in your Skrill account);
  • – Be issued within the last 3 months;
  • – Be received at your physical address.

 Please note: Due to PCI DSS (Payment Card Industry Data Security Standard) compliance requirements, we do not accept or process credit/debit card statements or any other documents with card information presented on them. Mobile telephone bills, envelopes, packages, magazines and advertisement materials with address stamps, as well as screen shots or printouts of content created online are not accepted also.

 You can upload the required document in the “My Account->Email support->Account/Security->You have requested information and/or documents from me” section on the website. The ticket ID is provided in the subject field of this e-mail.

 Finally, In order to ensure smooth withdrawal processing, we have contacted a senior customer representative who should amend your names registered on your Bank of China account in our system to zhao weining. Please be kindly informed that the estimated processing time frame for such cases may take up to 2 business days. 

 Important note: please be kindly asked not to process any withdrawals to your Bank of China account until we confirm that your names have been amended accordingly.

 We thank you for your cooperation in advance. Should you have any further questions or requests, feel free to contact us any time.

 Best regards,

XXX

Your Skrill team

在收不到验证码的情况下,MB提供人工验证。人工验证的方式是提供一个纸质文件的扫描。这个文件可以是户口本,银行个人账户报表或者其他的生活账单。这文件需要符合以下条件:

  • 名字和地址均清晰,而且和注册的地址一致。(MB方会翻译中文)
  • 文件发布在3个月内
  • 在你注册地址收到的

这文件不要包含任何卡的机密信息。没有人愿意卷入法律漩涡。不能是电脑伪造的文件。

依照邮件的指引,依次点击”My Account”->”Email support->”Account/Security”->”You have requested information and/or documents from me” 在打开的页面中上传扫描件。注意文件大小需小于1000K。上传文件后,页面的提交按钮就能显示。在ticketID中填入ticketID。这个ID可以在MB发送的邮件标题中找到。然后在文本框中留言(如果有需要则留言,礼貌上说说你需要对方帮忙验证地址会很好),点击提交。 MB客服大概在当天能给回复,2个工作日内能完成。实际上我当天就验证好了。

 

031813_1157_Elance12

地址验证后,能得到另外的2500欧对外上限提升。

 

031813_1157_Elance13

 

绑定提现银行账户

“Summary “,
找到”Bank account” 一行点击旁边的“Add”连接,打开添加页面,选择所在的国家为中国大陆,然后需要填入SWIFT CODE。SWIFT CODE 是银行在国际汇款中的唯一代号。如果你不知道SWIFT CODE,请联系你银行客服。依照指引完成绑定,应该不难。

 

031813_1157_Elance14

 

从Elance中打款到MB

是时候拿钱了。

登录Elance,依次点击“MANAGE -> Withdraw”, 在”Withdrawal Method” 中选择注册的MB账号,键入提现金额,然后确定。Elance大概需要1个工作日完成转账。MB收到款后会发送一封通知邮件到注册邮箱。让人激动的是这个过程没有分毫的手续费!

登录MB,
点击顶部主导航的“WITHDRAW”标签,选择绑定好的银行,键入需要提取的金额。然后进入下一步确认。这个过程并不复杂。MB收取手续费$2.33,需要大概3-5天时间完成国际电汇。

 

031813_1157_Elance15

 

这个过程只需要付$2.33手续费,比国内跨行还便宜。3-5天后,查询中行的交易记录,就可以看到汇款已经打入银行,这个过程丝毫没有中间行问题。国内银行收到汇款后可以进行结汇而变成天朝币。中行网上结售汇交易只在每日09:00—17:00受理,各位可以在此时间段处理。

 

031813_1157_Elance16

 

 

一些常问的问题

Q: 一定用中行?

并不一定。目前知道中行以及招行和MB之间有直接业务来往,转账到中行/招行被实践证明没有中间行费用。

 

还有其他问题?请加入我们讨论组一起讨论。QQ讨论群Elance讨论组(162095216)。——Elance 讨论组,
总有一组人和你一样。

 

【ps:鉴于weiny哥的博客被墙,我将weiny哥的大作搬来这里,以供未备梯子的选手参考】