PHP 调用 SHELL 需要注意的地方

最近需要从前端调用系统命令实现一些东西,然后返回到前端来。

思来想去,觉得 html <-> php <-> shell的模式应该不错。从html到php可以用ajax实现动态交互,但php调用shell的这个过程需要注意一些地方。在这里浪费了不少时间。

第一:调用方式

PHP提供共了3个专门的执行外部命令的函数:system(),exec(),passthru()。具体的用法Google一下已经很多了。

第二:权限问题

由于我的web项目是在apache目录下的,但apache并没有足够的权限执行一些诸如mkdir等命令,导致我拔一些东西并储存的时候毫无反应。简单的做法就是修改一下web项目所在目录权限就可以了。

比如

$ chmod -R 777 /home/www/example

 

MySQL 插入错误

MySQL insert error。。。。。。。。

 

一条简单的SQL语句,竟然插入错误:

INSERT INTO USER (id, describe) VALUES (‘David’, ‘diudiu’);

咋一看确实没错啊,瞅半天才发现,是由于table中有字段名是MySQL的保留字。这里就是‘describe’,报错也就理所当然了。

解决办法:
在关键字的地方加上反引号”`”,就是键盘1旁边的那个字符。

MySQL就是通过添加反引号来区别保留字。

上述修改为

INSERT INTO USER (id, `describe`) VALUES (‘David’, ‘diudiu’);

即可。

 

 

PHP调用C/C++动态链接库

摘要

有时候,单纯依靠 PHP “本身”是不行的。尽管普通用户很少遇到这种情况,但一些专业性的应用则经常需要将 PHP 的性能发挥到极致(这里的性能是指速度或功能)。由于受到 PHP 语言本身的限制,同时还可能不得不把庞大的库文件包含到每个脚本当中。因此,某些新功能并不是总能被顺利实现,所以我们必须另外寻找一些方法来克服 PHP 的这些缺点。

了解到了这一点,我们就到了应该接触一下 PHP 的心脏并探究一下它的内核——可以编译成 PHP 并让之工作的 C 代码——的时候了。

概述:

PHP调用动态链接库几个必要步骤为:

1. C/C++编写动态链接库,编译打包成.so文件

2. 初始化一个新的PHP扩展

3. 配置、编写PHP扩展内容,在扩展中使用C/C++调用.so

4. 编译并添加PHP扩展

5. 在PHP应用中直接调用PHP扩展里暴露出来的API

为了从能运行的最简单的例子开始,所以下面的叙述可能不会严格按照上面列的步骤来写,也有可能会重复穿插着写。但总体顺序是一致的。

一. C/C++编写动态链接库,编译打包成.so文件

如果还不会用C++调用自己写的.so库,请参考我的这篇文章:

http://keping.me/cpp_invoke_so/

文中从什么是Name Mangling开始,到如何用调用一个包含简单函数的so库,再到如何从so中加载类,都有详细叙述,并附有可运行示例代码。

二. 初始化PHP扩展

本文中,我们将创建一个叫“vehicle”的PHP扩展,其中包含一个“Car”类。

将要创建的扩展会涉及到以下文件需要修改,这些文件将会出现在vehicle目录下。后面会一一叙述这些文件是怎么来的,现在只是大致了解一下。

  • car.h —— 包含了C++写的类,即Car的定义
  • car.cc —— Car类的具体实现
  • php_vehicle.h —— 包含了PHP创建扩展所需要的一些头文件,外部变量定义等。
  • vehicle.cc —— 扩展的主要源码文件,这里面会调用到Car类
  • config.m4 —— PHP扩展的配置文件

1. 需要PHP源码包

如果你不是通过源码包方式安装的PHP,而是通过apt-get install 安装的,那么首先确保你安装了 php-devel 包,然后需要下载php源代码,然后可以跳到第2步。

如果想从源码包编译安装PHP,可以参考我写的另外一篇文章《Linux(Ubuntu12.10)搭建PHP开发环境(源码包方式)》,有详细的每一步的介绍。地址为:

http://keping.me/linux-php-dev-by-source-style/

安装完成以后,跳到第2步。

2. 制作PHP外部扩展

去到PHP源码包目录的ext目录下,我的在

/usr/local/src/php-5.3.22/ext

然后输入命令

sudo ./ext_skel –extname=vehicle

该命令会在ext目录下新建一个vehicle目录,并创建新模块“vehicle”目前所需的所有文件,包括

config.m4, php_vehicle.h, vehicle.php, CREDITS等。

还会列出应该执行哪些后续步骤来使用新的扩展,具体如下图所示。

Selection_190

图中我一共使用了三个命令

$ pwd 显示我的php源码包的ext目录所在位置

$ sudo ./ext_skel –extname=vehicle 前面已解释

$ ls 列出了执行上一条命令以后,在vehicle目录下,为我们创建的文件及目录。

如上图所示,在它的指导步骤1~8中,大致了解到我们需要编译config.m4文件,然后需要运行配置,然后需要使用make命令编译等。现在不用知道具体都干些什么,接下来会分别叙述。

三. 配置、搭建最基本的PHP扩展骨架

1. 配置PHP构建系统——编写config.m4

首先我们需要明确的是,为了在PHP扩展中使用C++,那么必须通知PHP构建系统使用C++编译器

通过在config.m4 文件中添加宏PHP_REQUIRE_CXX()来实现。

使用C++的过程中,肯定会用到C++的一些库,至少需要标准库(libstdc++ 大多系统都是这样的)

通过在config.m4 文件中添加宏PHP_ADD_LIBRARY()来实现。

将下面的代码添加到config.m4中

PHP_ARG_ENABLE(vehicle,
    [Whether to enable the "vehicle" extension],
    [  --enable-vehicle      Enable "vehicle" extension support])

if test $PHP_VEHICLE != "no"; then
    PHP_REQUIRE_CXX()
    PHP_SUBST(VEHICLE_SHARED_LIBADD)
    PHP_ADD_LIBRARY(stdc++, 1, VEHICLE_SHARED_LIBADD)
    PHP_NEW_EXTENSION(vehicle, vehicle.cc car.cc, $ext_shared)
fi

即去掉config.m4文件中某些行前面的注释符号“dnl”,然后添加我们需要的配置。如果还不清楚,可以参考我的配置文件,内容如下图

Selection_191

这里的宏PHP_SUBST()是标准autoconf的AC_SUBST()宏的php修改版, 它在将扩展构建为共享模块时需要。

PHP_NEW_EXTENSION宏中,第一个参数代表模块的名称;第二个参数是需要编译的文件,用空格隔开;第三个参数跟宏PHP_SUBST()是一样的。

2. 编写头文件php_vehicle.h

该头文件应该包含以下内容,其中PHP_VEHICLE_EXTNAME “vehicle” 代表该扩展的名称,PHP_VEHICLE_EXTVER则代表版本号,这些都会在php_info()中显示出来。

#ifndef PHP_VEHICLE_H
#define PHP_VEHICLE_H

#define PHP_VEHICLE_EXTNAME  "vehicle"
#define PHP_VEHICLE_EXTVER   "1.0"

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif 

extern "C" {
#include "php.h"
}

extern zend_module_entry vehicle_module_entry;
#define phpext_vehicle_ptr &vehicle_module_entry;

PHP_MINIT_FUNCTION(vehicle);
PHP_MSUTDOWN_FUNCTION(vehicle);
PHP_RINIT_FUNCTION(vehicle);
PHP_RSHUTDOWN_FUNCTION(vehicle);
PHP_MINFO_FUNCTION(vehicle);

#endif /* PHP_VEHICLE_H */

我的php_vehicle.h文件内容如下图所示。

Selection_193

要理解PHP_MINIT_FUNCTION()函数,就需要了解PHP的启动步骤。大体就是

  • 当我们启动Apache的时候,它就启动PHP的解释器
  • PHP会调用每一个扩展的MINIT函数,可以通过查看php.ini文件来看哪些扩展模块是激活的
  • MINIT就是Module Initialization,即模块初始化方法的简称,在每一个模块初始化方法里,会定义并初始化一系列在以后的页面请求中需要用到的函数、类、变量等。
  • 一个典型的MINIT方法框架如下所示

[php]
PHP_MINIT_FUNCTION(extension_name) {

/* Initialize functions, classes etc */

}
[/php]

以上是PHP启动的第一步。为了先跑通整个流程,这里就不在一一叙述每一个方法以及宏的作用了。

3. 编写需要编译的文件(vehicle.cc、car.cc)

使扩展能够运行的最基本的vehicle.cc框架应该包含以下内容

#include "php_vehicle.h"

PHP_MINIT_FUNCTION(vehicle)
{
    return SUCCESS;
}

zend_module_entry vehicle_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
    STANDARD_MODULE_HEADER,
#endif
    PHP_VEHICLE_EXTNAME,
    NULL,                  /* Functions */
    PHP_MINIT(vehicle),
    NULL,                  /* MSHUTDOWN */
    NULL,                  /* RINIT */
    NULL,                  /* RSHUTDOWN */
    NULL,                  /* MINFO */
#if ZEND_MODULE_API_NO >= 20010901
    PHP_VEHICLE_EXTVER,
#endif
    STANDARD_MODULE_PROPERTIES
};

#ifdef COMPILE_DL_VEHICLE
extern "C" {
ZEND_GET_MODULE(vehicle)
}
#endif

我的vehicle.cc文件如下图所示

Selection_197

有了这个文件,我们还不能能创建最基本的PHP扩展,因为前面我们在配置文件config.m4中指定了需要编译的还有car.cc文件,所以必须给出,即使现在里面什么也没有。

所以还需要新建一个car.cc文件,暂时让它空着。

4. 配置、编译、安装

在当前文件目录(即/usr/local/src/php-5.3.22/ext/vehicle)下执行命令

$ sudo /usr/local/php/bin/phpize

$ sudo ./configure –enable-vehicle –with-php-config=/usr/local/php/bin/php-config

如下图所示

Selection_195

然后执行make & make install 命令

$ sudo make

$sudo make install

Selection_196

安装完成以后,会看到在

/usr/local/php/lib/php/extensions/no-debug-zts-20090626/

目录下有一个新生成的so文件,名为vehicle.so,将库该文件的路径添加到php.ini配置文件中,如下图所示。

Selection_199

即添加这句话

“extension=”/usr/local/php/lib/php/extensions/no-debug-zts-20090626/vehicle.so”

然后重启你的apache,在phpinfo()中就可以看到已经成功启动扩展vehicle了,如下图所示。

Selection_200

至此,最基本的框架已经搭起来了。接下来要做的工作就是如何使用PHP调用C/C++编写的so文件。先从简单的直接调用开始

四. 编写具体的PHP扩展内容

1.  编写car.h头文件

把头文件与源码文件分开是一个不错的习惯,特别是在别人不想知道你的具体实现的时候。这里我们也采取这种方式。

#ifndef VEHICLE_CAR_H
#define VEHICLE_CAR_H

// A very simple car class
class Car {
public:
    Car(int maxGear);
    void shift(int gear);
    void accelerate();
    void brake();
    int getCurrentSpeed();
    int getCurrentGear();
private:
    int maxGear;
    int currentGear;
    int speed;
};

#endif /* VEHICLE_CAR_H */

如上代码所示,我们先定义一个Car类,然后定义几个public的方法以及私有成员变量。然后在car.cc中实现它

#include "car.h"

Car::Car(int maxGear) {
    this->maxGear = maxGear;
    this->currentGear = 1;
    this->speed = 0;
}

void Car::shift(int gear) {
    if (gear < 1 || gear > maxGear) {
        return;
    }
    currentGear = gear;
}

void Car::accelerate() {
    speed += (5 * this->getCurrentGear());
}

void Car::brake() {
    speed -= (5 * this->getCurrentGear());
}

int Car::getCurrentSpeed() {
    return speed;
}

int Car::getCurrentGear() {
    return currentGear;
}

现在我们已经定义好了Car类,那么如何使其暴露给PHP用户空间,让PHP能够调用这些方法呢。

首先你需要定义一个包含有function_entry 表的PHP类来调用Car,这个function_entry 表里就包含了每一个你想暴露给PHP的C++方法。这里所指的这个PHP类就是前面提到的vehicle.cc。更新一下vehicle.cc的内容,如下所示。

#include "php_vehicle.h"

zend_class_entry *car_ce;

PHP_METHOD(Car, __construct)
{
}
PHP_METHOD(Car, p_shift)
{
}
PHP_METHOD(Car, p_accelerate)
{
}
PHP_METHOD(Car, p_brake)
{
}
PHP_METHOD(Car, p_getCurrentSpeed)
{
}
PHP_METHOD(Car, p_getCurrentGear)
{
}

function_entry car_methods[] = {
    PHP_ME(Car,  __construct,     NULL, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
    PHP_ME(Car,  p_shift,           NULL, ZEND_ACC_PUBLIC)
    PHP_ME(Car,  p_accelerate,      NULL, ZEND_ACC_PUBLIC)
    PHP_ME(Car,  p_brake,           NULL, ZEND_ACC_PUBLIC)
    PHP_ME(Car,  p_getCurrentSpeed, NULL, ZEND_ACC_PUBLIC)
    PHP_ME(Car,  p_getCurrentGear,  NULL, ZEND_ACC_PUBLIC)
    {NULL, NULL, NULL}
};

PHP_MINIT_FUNCTION(vehicle)
{
    zend_class_entry ce;
    INIT_CLASS_ENTRY(ce, "Car", car_methods);
    car_ce = zend_register_internal_class(&ce TSRMLS_CC);
    return SUCCESS;
}

zend_module_entry vehicle_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
    STANDARD_MODULE_HEADER,
#endif
    PHP_VEHICLE_EXTNAME,
    NULL,        /* Functions */
    PHP_MINIT(vehicle),        /* MINIT */
    NULL,        /* MSHUTDOWN */
    NULL,        /* RINIT */
    NULL,        /* RSHUTDOWN */
    NULL,        /* MINFO */
#if ZEND_MODULE_API_NO >= 20010901
    PHP_VEHICLE_EXTVER,
#endif
    STANDARD_MODULE_PROPERTIES
};

#ifdef COMPILE_DL_VEHICLE
extern "C" {
ZEND_GET_MODULE(vehicle)
}
#endif

可以看到在PHP_METHOD中的函数名称与Car.cc类里写的函数名称并不需要一样,你可以定义任意自己觉得合适的函数名,为了表示方便,我这里一律添加前缀”p_”。这里每一个函数都还没有具体实现。

前面提到的function_entry表在上诉代码中可以看到由很多PHP_ME组成,每一个都代表了想要暴露给PHP用户空间的方法,最后一定以{NULL,NULL,NULL}表示结束。

现在我们已经有了C++的类,也有了PHP类,那么如何把两者联系起来呢?

首先你需要做的是定义一个zend_object_hander。然后定义一个结构,该结构包含了这个hander和C++的类。在PHP5中一个object其实就是一个hander,可以如下定义。

zend_object_handlers car_object_handlers;

struct car_object {
    zend_object std;
    Car *car;
};

该结构就会把C++的对象与zend的对象联系起来,然后你需要把下列代码添加到你的vehicle.cc文件中去,在PHP_METHOD方法之前。

void car_free_storage(void *object TSRMLS_DC)
{
    car_object *obj = (car_object *)object;
    delete obj->car; 

    zend_hash_destroy(obj->std.properties);
    FREE_HASHTABLE(obj->std.properties);

    efree(obj);
}

zend_object_value car_create_handler(zend_class_entry *type TSRMLS_DC)
{
    zval *tmp;
    zend_object_value retval;

    car_object *obj = (car_object *)emalloc(sizeof(car_object));
    memset(obj, 0, sizeof(car_object));
    obj->std.ce = type;

    ALLOC_HASHTABLE(obj->std.properties);
    zend_hash_init(obj->std.properties, 0, NULL, ZVAL_PTR_DTOR, 0);
    zend_hash_copy(obj->std.properties, &type->default_properties,
        (copy_ctor_func_t)zval_add_ref, (void *)&tmp, sizeof(zval *));

    retval.handle = zend_objects_store_put(obj, NULL,
        car_free_storage, NULL TSRMLS_CC);
    retval.handlers = &car_object_handlers;

    return retval;
}

然后更新一下PHP_MINIT_FUNCTION,这个函数前面提到过,就是PHP的扩展的模块初始化函数,如下所示:

PHP_MINIT_FUNCTION(vehicle)
{
    zend_class_entry ce;
    INIT_CLASS_ENTRY(ce, "Car", car_methods);
    car_ce = zend_register_internal_class(&ce TSRMLS_CC);
    car_ce->create_object = car_create_handler;
    memcpy(&car_object_handlers,
        zend_get_std_object_handlers(), sizeof(zend_object_handlers));
    car_object_handlers.clone_obj = NULL;
    return SUCCESS;
}

可能这里对“TSRMLS_DC”这个宏比较疑惑,它其实是 “ , void ***tsrm_ls”

然后编写一下构造函数

PHP_METHOD(Car, __construct)
{
    long maxGear;
    Car *car = NULL;
    zval *object = getThis();

    if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &maxGear) == FAILURE) {
        RETURN_NULL();
    }

    car = new Car(maxGear);
    car_object *obj = (car_object *)zend_object_store_get_object(object TSRMLS_CC);
    obj->car = car;
}

接着实现一下前面定义好的,但没有写内容的PHP_METHOD函数。为了演示的简洁,我们就实现两个函数。

PHP_METHOD(Car, p_accelerate)
{
    Car *car;
    car_object *obj = (car_object *)zend_object_store_get_object(
        getThis() TSRMLS_CC);
    car = obj->car;
    if (car != NULL) {
        car->accelerate();
    }
}

PHP_METHOD(Car, p_getCurrentSpeed)
{
    Car *car;
    car_object *obj = (car_object *)zend_object_store_get_object(
        getThis() TSRMLS_CC);
    car = obj->car;
    if (car != NULL) {
        RETURN_LONG(car->getCurrentSpeed());
    }
    RETURN_NULL();
}

记得添加所需要的头文件car.h。

然后重新 make & make install 吧,做完以后重启Apache服务器。

五. 在PHP脚本中调用扩展暴露出来的方法

编写一个PHP脚本,去测试是否成功。测试代码如下

[php]

<?php
// create a 5 gear car
$car = new Car(5);
print $car->p_getCurrentSpeed(); // prints ‘0’
$car->p_accelerate();
print $car->p_getCurrentSpeed(); // prints ‘5’
?>

[/php]

运行结果如果是0 和 5就说明成功了。

自此一个简单的PHP调用C++类已经实现了。

六. 在扩展中调用C/C++写的so库

假设现在我们有一个冒泡排序的.so库文件,现在我们想在PHP扩展中调用这个库文件里的函数

[cpp]
extern "C" void bubble_sort(int *arr, int len)
{
int tmp;

for(int i = 0; i < len – 1; i++)
for(int j = i + 1; j < len; j++)
{
if(arr[i] > arr[j])
{
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
}
[/cpp]

1. 更新car.h文件以及car.cc文件,添加调用so的代码,如下图所示。

Selection_201

car.cc 中代码如下图所示。

Selection_202

2. 更新vehicle.cc文件

在function_entry car_methods添加

PHP_ME(Car, p_bubble_sort_so, NULL, ZEND_ACC_PUBLIC)

然后添加一个PHP_METHOD(Car, p_bubble_sort_so),代码如下

[php]
PHP_METHOD(Car, p_bubble_sort_so)
{
zval *arr;
zval *len;
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "zz", &arr, &len) == FAILURE)
{
return;
}
switch (Z_TYPE_P(arr)) {
case IS_NULL:
php_printf("NULL\n");
break;
case IS_BOOL:
php_printf("Boolean: %s\n", Z_LVAL_P(arr) ? "TRUE" : "FALSE");
break;
case IS_LONG:
php_printf("Long: %ld\n", Z_LVAL_P(arr));
break;
case IS_DOUBLE:
php_printf("Double: %f\n", Z_DVAL_P(arr));
break;
case IS_STRING:
php_printf("String: ");
PHPWRITE(Z_STRVAL_P(arr), Z_STRLEN_P(arr));
php_printf("\n");
break;
case IS_RESOURCE:
php_printf("Resource\n");
break;
case IS_ARRAY:
php_printf("Type is Array\n");
break;
case IS_OBJECT:
php_printf("Object\n");
break;
default:
php_printf("Unknown\n");
}

HashTable *arr_hash;
HashPosition pointer;
int array_count;
zval **data;

arr_hash = Z_ARRVAL_P(arr);
array_count = zend_hash_num_elements(arr_hash);
php_printf("The array passed contains %d elements\n", array_count);

// pass to the so
int *arr_so = (int*)malloc(sizeof(int) * array_count);
int len_so = array_count;
int i= 0;

for(zend_hash_internal_pointer_reset_ex(arr_hash, &pointer);
zend_hash_get_current_data_ex(arr_hash, (void**) &data, &pointer) == SUCCESS;
zend_hash_move_forward_ex(arr_hash, &pointer))
{
if (Z_TYPE_PP(data) == IS_LONG)
{
php_printf("%ld\t%ld\n", Z_LVAL_PP(data), (**data).value.lval);
arr_so[i++] = Z_LVAL_PP(data);
}
}

Car *car;
car_object *obj = (car_object*)zend_object_store_get_object(
getThis() TSRMLS_CC);
car = obj->car;
if (car != NULL)
{
car->bubble_sort(arr_so, len_so);
}
for(i = 0; i < len_so; i++)
{
php_printf("%d\n", arr_so[i]);
}
}

[/php]

这段代码还是比较容易懂的,可能会对zval这个变量不熟悉。其实所有用户定义的变量在PHP中都是用zval类型来表示的,它的内部表示如下

[c]
typedef pval zval;

typedef struct _zval_struct zval;

typedef union _zvalue_value {
long lval; /* long value */
double dval; /* double value */
struct {
char *val;
int len;
} str;
HashTable *ht; /* hash table value */
struct {
zend_class_entry *ce;
HashTable *properties;
} obj;
} zvalue_value;

struct _zval_struct {
/* Variable information */
zvalue_value value; /* value */
unsigned char type; /* active type */
unsigned char is_ref;
short refcount;
};
[/c]

然后再看上面那段代码。

switch里面是写给大家的说明程序,为了展示出如何判断传入的参数类型,可以不写略过。下面这句printf代码也是为了向大家展示 Z_LVAL_PP的用法,它其实就是对指针的指针取值,你也可以写成后面一种形式,即使**data的形式。不过建议使用第一种。

php_printf("%ld\t%ld\n", Z_LVAL_PP(data), (**data).value.lval);

接着看代码。首先我们用zend_parse_parameters接收穿过来的参数,这里我们传递的是数组。PHP中数组在zval里都是以hash表的形式储存的,所以我们这里声明一个hash表来接收这个参数。通过zend_hash_num_elements()则可以得到hash表元素的个数,也就是数组的个数。

然后我们将传递过来的参数通过for循环复制给我们的数组,最后通过调用car的bubble_sort函数进行排序。而bubble_sort调用的就是写好的so库函数了。

3. 编译、安装、测试

重新 make & make install,然后写一个PHP脚本测试一下,可以如下写:

Selection_203

然后运行该PHP脚本,如果浏览器里出现了排序后的数列0,1,2,3,4,5,则代表成功了。

That’s all,

Enjoy!

参考文献

[1]       Al-Qahtani, S. S., Arif, R., Guzman, L. F., Pietrzynski, P., & Tevoedjre, A. (2010). Comparing selected criteria of programming languages java, PHP, C++, perl, haskell, AspectJ, ruby, COBOL, bash scripts and scheme revision 1.0.Cornell University.

[2]       Sterling Hughes. Extending PHP [J]. Web Techniques, 2001, 6(1), 56 – 60.

[3]       PHP, http://www.php.net/manual/en/internals2.structure.php

[4]       Wikipedia, PHP, https://en.wikipedia.org/wiki/PHP

[5]       C++ dlopen mini HOWTO, http://www.isotton.com/devel/docs/C++-dlopen-mini-HOWTO/C++-dlopen-mini-HOWTO.html#theproblem

[6]       Extension Writing Part I: Introduction to PHP and Zend, http://devzone.zend.com/303/extension-writing-part-i-introduction-to-php-and-zend/

[7]       Wrapping C++ Classes in a PHP Extension, http://devzone.zend.com/1435/wrapping-c-classes-in-a-php-extension/

[8]       PHP Extensions – How and Why?, http://abhinavsingh.com/blog/2008/12/php-extensions-how-and-why/

[9]       How does PHP echo’s a “Hello World”? – Behind the scene, http://abhinavsingh.com/blog/2008/11/how-does-php-echos-a-hello-world-behind-the-scene/

[10]      Zend API:Zend_parse_parameters, http://zhaojunjie.blog.51cto.com/5475365/945302

[11]     【翻译】PHP扩展编写第二步:参数,数组,以及ZVAL, http://weizhifeng.wordpress.com/2011/07/20/extension-writing-part2-parameters-arrays-and-zvals/

[12]      php扩展 c,传参,传数组,zvar类型,全局变量, http://donbe.blog.163.com/blog/static/1380480212010225113531433/

[13]      A Close Look Into PHP Zval, http://blog.jjyao.me/blog/2013/03/17/a-close-look-into-php-zval/

[14]      convert_to_xxx系列函数帮助我们进行类型转换, http://9212219.i.sohu.com/blog/view/175458610.htm

[15]       深入理解php内核 编写扩展 II:参数、数组和ZVALs, http://blog.csdn.net/hguisu/article/details/7377235

[16]       Zend API:深入 PHP 内核, http://xiaobin.net/wp-content/uploads/2011/09/zend/

PHP与C++性能比较

PHP是速度很快的脚本语言,但是用了框架以后好像感觉挺慢的。于是猜测会不会PHP本身也不是很快。如果不是很快,能否采用PHP调用本地动态链接库的形式来提升速度。 于是有了下面的对比实验。

测试环境

1. 硬件环境如下图所示。

Selection_186

2. 软件环境

系统: Ubuntu 12.10

gcc版本:

Thread model: posix
gcc version 4.7.2 (Ubuntu/Linaro 4.7.2-2ubuntu1)

php版本:

PHP 5.3.22 (cli) (built: Mar 14 2013 20:37:16)
Copyright (c) 1997-2013 The PHP Group
Zend Engine v2.3.0, Copyright (c) 1998-2013 Zend Technologies

php开发环境: LAMP,所有安装包均是通过源码编译安装而成,编译过程中会自动根据本机各项参数进行最优配置。性能比apt-get install命令直接安装好。 关于以源码包方式搭建LAMP请参考文章:http://keping.me/linux-php-dev-by-source-style/

测试方法

由于冒泡排序在时间复杂度上相当稳定——O(n2),在最大程度上减少了数据可能带来的影响,故采取计算冒泡排序的运行时间的方法来进行此次实验。

对比测试分组

分组1: C++直接调用程序内的函数

分组2: C++调用打包好的动态链接库文件(.so文件,该文件也是自己写好并打包)

分组3: PHP直接调用程序内的函数

分组4: PHP调用打包好的动态链接库文件(.so文件,该文件也是自己写好并打包)

测试数据

数据总体规模为5,500,000个0~999的整数。

每一实验组,循环执行次数为30250,000,000,000次。

测试所用数据可以从以下地址下载:

http://keping.me/david-uploads/data/data_cpp.tar.gz

测试数据生成代码如下

[cpp]
#include
#include
#include

using std::cout;
using std::endl;
int main (int argc, char *argv[])
{
int scale;

scale = atoi(argv[1]);      // argv[1] will be 10000, 20000 … 90000, 100000

srand(unsigned(time(0)));   // use the UNIX timestamp as seeds
for(int i = 1; i <= scale; i++)
{
cout << rand() % 1000 << "\t";
if(i % 10 == 0) cout << endl;
}
}
[/cpp]

可以看到是0~999的整数,一共有10种测试数据的规模,分别放在十个不同目录下,如下图所示

Selection_159

目录名称代表数据的规模,如data_90000 表示数据规模为90,000个,同理data_100000表示数据规模为100,000个,依次类推。每一个目录下面包含10组测试数据,以data_100000举例,如下图所示

Selection_161

每个文件则包含100,000个0~999的随机数

Selection_163

数据文件打包下载地址:  地址1(包含数据以及 “分组1” 的测试结果)

以下是对比测试。

首先是 “分组1” 的测试

为了尽量保证算法一致,所以没有采用指针等数据结构,变量的交换也采用最原始的设置中间变量机制,关键代码如下:

[cpp]
void bubble(int *arr, int len)
{
int tmp;

for(int i = 0; i < len – 1; i++)
{
for(int j = i + 1; j < len; j++)
{
if(arr[i] > arr[j])
{
tmp = arr[i];
arr[i] = arr[j];
arr[j] = tmp;
}
}
}
}

[/cpp]

以下是data_100000目录下num_1数据文件的运行结果文件result_1的部分截图, 用时13.74秒

Selection_164

第一行输出记录的是每一秒中所含的时钟数;第二行记录的是排序开始之前程序已经运行的时钟数;第三行记录的是排序结束以后程序运行的时钟数;第四行则可以根据前面的数据得出本次排序运行的时间,以秒记,保留两位小数便于对比。

下表则是data_100000目录下的所有数据文件(num_1 至 num_9)的运行结果

cpp_y

可以看到,对于100,000级别的数据,进行冒泡排序, “分组1” 用了大约13.8秒左右的时间。下面将给出对于不同数据规模(data_10000~data_100000)的平均测试数据

cpp_average

其中X轴方向上表示数据规模为 10K(即使10,000),20K,,,100K的测试数据。
其中Y轴方向上表示测试的平均时间,对每一数据规模均有10个测试数据,此处为平均值。
从图中可以看出,结果基本符合 y=x的函数曲线,冒泡排序还是相当稳定的。。。

分组2的测试 

目录结构如下,其中libbubble.so文件即为冒泡排序打包成动态链接库。将会在main函数中调用。分组2与分组1的主要区别也在此,分组1中是在main里调用本地的冒泡排序函数,而分组2则是通过调用.so文件中的冒泡排序函数。

Selection_180

运行的测试数据来源与“测试分组1”完全一致,测试结果储存在相应目录下,如下图所示。

Selection_179

将测试结果的数据处理以后,得到下图。

cpp_so_average

速度竟然比C++调用自己内部的函数更快,估计是打包成动态链接库的时候,编译器已经做了优化。

分组3的测试

接下来是PHP执行冒泡排序的测试。

目录结构如下图所示,将调用PHP写的冒泡排序函数进行数据测试。 关

Selection_181

关键代码如下

[php]
for($i = 0; $i < $len – 1; $i++)
{
for($j = $i + 1; $j < $len; $j++)
{
if($arr[$i] > $arr[$j])
{
$tmp = $arr[$i];
$arr[$i] = $arr[$j];
$arr[$j] = $tmp;
}
}
}
[/php]

可以看到,为了保证算法上的一致性,代码结构与实验分组一是一样的。

由于实在是比较慢,所以写了一个shell脚本来执行,shell脚本如下图所示(未完整截图)

Selection_182

将分组3的测试结果的数据处理以后,得到下图。

php_average

可以看到在相同数据规模下,分组3的运行时间要远远大于分组1以及分组2,并且随着数据规模的上升,总体呈现出上升趋势。

分组4的测试

分组4与分组3的区别在于:分组4则是调用以C++编写的动态链接库中的冒泡排序算法,并将该动态链接库以扩展的形势添加到了PHP系统中;分组3则是直接调用PHP写的冒泡排序算法。

将分组4的测试结果的数据处理以后,得到下图。

php_so_average

可以看到虽然还是PHP进行冒泡排序算法,但是效率得到了极大的提高。

最后是对比图

首先看一下数据表

QQ图片20130620232930

其中10000,20000, …, 100000代表数据规模,表中数据为执行的秒数。可以看到分组3,也就是PHP分组,大约是其他分组的100倍至170倍时间。以至于如果不采取log函数,将完全看不到其他三个分组的图。下图是对上表每个数据取以10为底的对数以后,得到的数值描绘的图。

QQ图片20130620230529

大致结论,PHP执行速度很慢,如果实在要采取PHP的方式,请采用将C/C++编写的动态链接库,经过Zend API的转化添加成PHP扩展,PHP再调用该扩展的形势,性能如分组4所示,是非常快的。

参考文献

[1]       Al-Qahtani, S. S., Arif, R., Guzman, L. F., Pietrzynski, P., & Tevoedjre, A. (2010). Comparing selected criteria of programming languages java, PHP, C++, perl, haskell, AspectJ, ruby, COBOL, bash scripts and scheme revision 1.0.Cornell University.

[2]       Sterling Hughes. Extending PHP [J]. Web Techniques, 2001, 6(1), 56 – 60.

[3]       PHP, http://www.php.net/manual/en/internals2.structure.php

[4]       Wikipedia, PHP, https://en.wikipedia.org/wiki/PHP

Compile and Install LAMP(Linux/Apache/MySQL/PHP) from source on Ubuntu 12.10

This blog will guide you finish the compiling and installing a LAMP Server from source on Ubuntu step by step.

Of course, it will take you a little much time(Thanks for the 15 source packages ) ,so a cup of coffee will be a good choice 🙂

Zeroth. Here follows some source packages, which will be used when we build the LAMP.Some of them are the newest, others not.

1. httpd-2.4.4

2. mysql-5.6.10

3. php.5.3.22

4. libxml2-2.6.30

5. libmcrypt-2.5.8

6. zlib-1.2.7

7. gd-2.0.35

8. autoconf-2.61

9. freetype-2.3.5

10. libpng-1.6.0

11. jpeg-6b

12. apr-1.4.6

13. apr-util-1.4.1

14. pcre-8.32

15. libtool-2.2.6

First. check the basic system info

1. $ uname -a:
Selection_103

2. check whether there is gcc or not
$ gcc -v
Selection_104
Whoops!!!There is not,but never mind ,just install it.
$ sudo apt-get install gcc

Now, we can begin to build all the source packages:)

Second. Compile and install the source packages

2.1 install the newest libxml2 library files
2.1.1 download the libxml2-2.6.30.tar.gz from the link above or the official site, and put it into the directory /usr/local/src/, then extract it to directory  libxml2-2.6.30/ and then get into that derectory. Command lines as follow:
$ cd /usr/local/usr/                                      // enter the directory which the source package lays
$ sudo tar zxvf libxml2-2.6.30.tar.gz         // extract it
$ cd libxml2-2.6.30/                                    // enter the directory

2.1.2 use command “configure” to check and configure the system environment and generate the configured files. Command lines as follow:
$ ./configure –prefix=/usr/local/libxml2
the option –prefix=/usr/local/libxml2 here is to tell the installer to install it to directory /usr/local/libxml2 .When it finished, there will be a tips “Done configuring”, as the pic shows below.
Selection_106

2.1.3 use  command “make” to compile and generate install files
$ sudo make                                                          // compile
Here comes a error:
In function ‘open’,inlined from ‘xmlNanoHTTPSave__internal_alias’ at nanohttp.c:1588:12:

/usr/include/x86_64-linux-gnu/bits/fcntl2.h:51:24: error: call to ‘__open_missing_mode’ declared with attribute error: open with O_CREAT in second argument needs 3 arguments

solution:
open and edit the nanohttp.c which is  on the current directory,see the 1588th line, and modify
fd = open(filename, O_CREAT | O_WRONLY);                   to
fd = open(filename, O_CREAT | O_WRONLY,0777);
as the pic shows below.
Selection_108

2.14 use command”make install” to install the software.Command lines as follow:
$ sudo make install                                               // install
if installed success, there will be 5 subdirectories bin, include ,lib, man and share under /usr/local/libxml2/, as the pic shows below.
Selection_109
*when we install php5 later, we’ll add “–with-libxml-dir=/usr/local/libxml2” to the configure options to  specify the location of  libxml2 library files.

2.2 install the newest libmcrypt library files
2.2.1 download the libmcrypt-2.5.8.tar.gz from the link above or the official site, and put it into the directory /usr/local/src/, then extract it to directory libxml2-2.6.30/ and then get into that derectory. Command lines as follow:
$ cd /usr/local/usr/                                      // enter the directory which the source package lays
$ sudo tar libmcrypt-2.5.8.tar.gz                // extract it
$ cd libxml2-2.6.30/                                    // enter the directory

2.2.2 use command “configure” to check and configure the system environment and generate the configured files. Command lines as follow:
$ ./configure –prefix=/usr/local/libmcrypt
the option –prefix=/usr/local/libmcrypt here is to tell the installer to install it to directory /usr/local/libmcrypt.
Here will use the g++ complier, and if there is not a g++, you should first do the sudo apt-get install g++ first.

2.2.3 use  command “make” to compile and generate install files
$ sudo make                                                          // compile

2.2.4 use command”make install” to install the software.Command lines as follow:
$ sudo make install                                              // install
if installed success, there will be 5 subdirectories bin, include ,lib, man and share under /usr/local/libmcrypt/, as the pic shows below.
Selection_110
*when we install php5 later, we’ll add “–with-mcrypt-dir=/usr/local/libmcrypt” to the configure options to  specify the location of  libmcrypt library files.

2.2.5 install the libltdl library files
when finished installing the libmcrypt, enter into the directory /usr/local/src/libmcrypt-2.5.8, and then enter the subdirectory libltdl. Follow the command lines below to finish the configure, compile and install:
$ cd /usr/local/src/libmcrypt-2.5.8/libltdl    // enter the directory which the source package lays
$ ./configure  –enable-ltdl-install                  // configure it
$ make                                                             // compile
$ make install                                                  // install
if installed success, there will be a header file ltdl.h under the directory /usr/local/include,as the pic show below.
Selection_112

2.3 install the newest zlib library files
2.3.1 download the zlib-1.2.7.tar.gz from the link above or the official site, and put it into the directory /usr/local/src/, then extract it to directory zlib-1.2.7/ and then get into that derectory. Command lines as follow:
$ cd /usr/local/usr/                                      // enter the directory which the source package lays
$ sudo tar zxvf zlib-1.2.7.tar.gz                  // extract it
$ cd zlib-1.2.7/                                             // enter the directory

2.3.2 use command “configure” to check and configure the system environment and generate the configured files. Command lines as follow:
$ ./configure
you’d better not use the option –prefix=/usr/local/zlib here, because it will lead to failing  to locate the zlib library when install libpng.

2.3.3 use  command “make” to compile and generate install files
$ sudo make                                                          // compile

2.3.4 use command”make install” to install the software.Command lines as follow:
$ sudo make install                                              // install
if installed success, there will be 3 subdirectories include ,lib and share under /usr/local/zlib/, as the pic shows below.
Selection_113*when we install php5 later, we’ll add “–with-zlib-dir=/usr/local/zlib” to the configure options to  specify the location of  zlib library files.

2.4 install the newest libpng library files

2.4.1 Download the file: libpng-1.6.0.tar.gz from the above link or the official site , put it under /usr/local/src/, and extract it to libpng-1.6.0/, then enter the directory using following command:

$ cd /usr/local/usr/                                      // enter the directory where the source code is
$ sudo tar zxvf libpng-1.6.0.tar.gz             // extract the file
$ cd libpng-1.6.0/                                        // enter the current directory

2.4.2 Check and configure the installation environment with “configure” command, which will generate installation configuration file.  The command line as follows:

$ ./configure –prefix=/usr/local/libpng

“–prefix=/usr/local/libpng” means that the installing software will be installed under /usr/local/libpng.

ERROR: configure: error: zlib not installed

Solution at this blog: http://keping.me/2013-3-12-2/ (see the English version… I don’t like this solution but it’s the only effective one I have ever found. 🙁 )

2.4.3 use the make command to compile the source file and generate the installation file:

$ make                                                          // compile

2.4.4 use command make install to install:

$ make install                                              // install

If the installation succeeded, there would be four directories(bin/, include/, lib/, share/)generated under /usr/local/libpng, as following picture:

* When installing the GD2 lib, it should add the option –with-png-dir=/usr/local/libpng behind configure command to locate the position of libpng file.

2.5 install the newest jpeg6 library files

2.5.1 Download the jpegsrc.v6b.tar.gz file from above link or the official site,  put it under /usr/local/src/, and extract it into  directory jpeg-6b/  and then enter the current directory jpeg-6b/. Commands as follows:

$ cd /usr/local/usr/                                      // enter the directory where the source file is
$ sudo tar zxvf jpegsrc.v6b.tar.gz              // extract the file
$ cd jpeg-6b/                                                // enter the current directory

2.5.2 We need to create the installation directory manually when installing the jpeg6 lib files before installing the GD2. The installation directory will not be created automatically. The command as follows:

$ sudo mkdir /usr/local/jpeg6                          // create a installation directory
$ sudo mkdir /usr/local/jpeg6/bin                   // create a directory saving commands
$ sudo mkdir /usr/local/jpeg6/lib                     // create a jpeg6 directory
$ sudo mkdir /usr/local/jpeg6/include              // create a directory saving header files
$ sudo mkdir -p /usr/local/jpeg6/man/man1   // create a directory saving manual

2.5.3 Check and configure the installation environment with “configure” command, which will generate installation configuration file.  The command line as follows: ( for displaying explicitly, use “\” to split the command for several lines):

$ sudo ./configure \
> –prefix=/usr/local/jpeg6/ \                // install the software into /usr/local/jpeg6
> –enable-shared \                                 // GUN’s libtool will be used when creating shared lib
> –enable-static                                       // GUN’s libtool will be used when creating static  lib

2.5.4 use the make command to compile the source file and generate the installation file:

$ make                                                          // compile

ERROR:

./libtool –mode=compile gcc -O2 -I. -c ./jcapimin.c
make: ./libtool: Command not found
make: *** [jcapimin.lo] Error 127

Solution:  http://keping.me/2013-4-12/ ( see the English version…:) )

2.5.5 use command make install to install:

$ make install                                              // install

* When installing the GD2 lib, it should add the option –with-jpeg-dir=/usr/local/jpeg6 behind configure command to locate the position of jpeg lib file.

So far, we have installed so many packages as following picture~~~Have a rest, please~~

2.6 install the newest freetype library files

2.6.1 Download the file freetype-2.3.5.tar.gz on the above link or the official site, put it under /usr/local/src/, and extract it into freetype-2.3.5/ and then enter the current directory. The commands as follows:

$ cd /usr/local/usr/                                      //  enter the directory where the source code is
$ sudo tar zxvf freetype-2.3.5.tar.gz          // extract the file
$ cd freetype-2.3.5/                                     // enter the current directory

2.6.2 Check and configure the installation environment with “configure” command, which will generate installation configuration file.  The command line as follows:

$ ./configure –prefix=/usr/local/freetype

“–prefix=/usr/local/freetype” means that the installing software will be installed under /usr/local/freetype.

2.6.3 use the make command to compile the source file and generate the installation file:
$make                                                      // compile

2.6.4 use command make install to install:
$ make install                                              // install

If the installation succeeded, there would be four directories(bin/, include/, lib/, share/)generated under /usr/local/freetype, as following picture:

* When installing the freetype lib, it should add the option –with-jpeg-dir=/usr/local/freetype behind configure command to locate the position of freetype lib file.

2.7 install the newest autoconf library files

2.7.1 Download the file autoconf-2.61.tar.gz on the above link or the official site, put it under /usr/local/src/, and extract it into autoconf-2.61/ and then enter the current directory. The commands as follows:

$ cd /usr/local/usr/            // enter the directory where the source code is
$ sudo tar zxvf autoconf-2.61.tar.gz          // extract the file
$ cd autoconf-2.61/                              // enter the current directory

2.7.2 Check and configure the installation environment with “configure” command, which will generate installation configuration file.  The command line as follows:
$ ./configure

ERROR: configure: error: GNU M4 1.4 is required

Solution: $ sudo apt-get install m4

2.7.3 use the make command to compile the source file and generate the installation file:
$make                                                      // compile

2.7.4 use command make install to install:
$ make install                                              // install

2.8 install the newest GD library files

2.8.1 Download the file gd-2.0.35.tar.gz on the above link or the official site, put it under /usr/local/src/, and extract it into gd-2.0.35/ and then enter the current directory. The commands as follows:

$ cd /usr/local/usr/            // enter the directory where the source code is
$ sudo tar zxvf gd-2.0.35.tar.gz          // extract the file
$ cd gd-2.0.35/                              // enter the current directory

2.8.2 Check and configure the installation environment with “configure” command, which will generate installation configuration file.  The command line as follows:

$ sudo ./configure \
> –prefix=/usr/local/gd2/ \                             // install the software into /usr/local/gd2
> –with-zlib=/usr/local/zlib/ \                         // locate zlib
> –with-jpeg=/usr/local/jpeg6/ \                    // locate jpeg6
> –with-png=/usr/local/libpng/ \                    // locate libpng
> –with-freetype=/usr/local/freetype/           // locate freetype 2.x font lib

2.8.3 use the make command to compile the source file and generate the installation file:
$make                                                      // compile

ERROR: gd_png.c:16:53: fatal error: png.h: No such file or directory

Solution: http://keping.me/2013-3-13/( see the English version 🙂 )

2.8.4 use command make install to install:
$ make install                                              // install

If the installation succeeded, there would be four directories(bin/, include/, lib/, share/)generated under /usr/local/gd2, as following picture:

* When installing the GD2 lib, it should add the option –with-jpeg-dir=/usr/local/gd2/ behind configure command to locate the position of GD lib file.

2.9 install the newest Apache server

2.9.1 Download the file httpd-2.4.4.tar.gz on the above link or the official site, put it under /usr/local/src/, and extract it into httpd-2.4.4/ and then enter the current directory. The commands as follows:

$ cd /usr/local/usr/            // enter the directory where the source code is
$ sudo tar zxvf  httpd-2.4.4.tar.gz          // extract the file
$ cd httpd-2.4.4/                              // enter the current directory

2.9.2 Check and configure the installation environment with “configure” command, which will generate installation configuration file.  The command line as follows: ( for displaying explicitly, use “\” to split the command for several lines):

$ sudo ./configure \
> –prefix=/usr/local/apache2 \                // specify the installation location of Apache
> –sysconfdir=/etc/httpd  \                             // specify the location saving configuration files of Apache server
> –with-z=/usr/local/zlib/ \                             // specify the location of zlib
> –with-included-apr  \                                    // using the copy of bundled APR / APR-Util
> –disable-userdir \                                          // requests mapped to user-specific directories
> –enable-so \                                                   // compiled as dynamic sharing object(DSO)
> –enable-deflate=shared \                             // reduce the support of transmission encoding
> –enable-expires=shared \                            // support the control of the header files expiration
> –enable-rewrite=shared \                            // url control based on rules
> –enable-static-support                                 // create a support of a statically linked version

ERROR: configure: error: Bundled APR requested but not found at ./srclib/. Download and unpack the corresponding apr and apr-util packages to ./srclib/.

Solution: http://keping.me/2013-3-13-2/ (see the English version 🙂 )

2.9.3  use the make command to compile the source file and generate the installation file:
$make                                                      // compile

2.9.4 use command make install to install:
$ make install                                              // install

If the installation succeeded, there would be twelve directories(bin/, build/, cgi-bin/, error/, htdocs/, icons/, include/, lib/, logs/, man/, manual/, modules/)generated under /usr/local/apache2, as following picture:

2.9.5 Start Apache server using following command:

$ sudo /usr/local/apache2/bin/apachectl start

ERROR: AH00558: httpd: Could not reliably determine the server’s fully qualified domain name, using 127.0.1.1. Set the ‘ServerName’ directive globally to suppress this message

Solution: modify the file httpd.conf under the directory /etc/httpd( the location specified when installing Apache server), as following picture:

and use following command to modify the file:

$ sudo vim /etc/httpd/httpd.conf

find the location of ServerName, as following picture:

add a line “ServerName localhost” under the ServerName, as following picture:

Restart Apache server with following command:

sudo /usr/local/apache2/bin/apachectl restart

To check whether it started successfully, use the grep command:

$ ps -ef | grep httpd

If there are 4/5 lines output, it started successfully, as following picture:

Also, we can check it by entering “localhost” in the your browser. If succeeded, the following content will occur:

2.9.6 Run on startup

Each server software need to be configured to run on startup. About Apache, we just need to add the start command line of Apache server in the file “/etc/rc.local”. Command as follows:

$ sudo vim /etc/rc.local

2.10 install the Mysql

2.10.1 Download the file mysql-5.6.10.tar.gz on the above link or the official site, put it under /usr/local/src/, and extract it to mysql-5.6.10/, and enter the current directory. The commands as follows:
$ cd /usr/local/usr/            // enter the directory where the source code is
$ sudo tar zxvf  mysql-5.6.10.tar.gz         // extract the file
$ cd mysql-5.6.10/                              // enter the current directory

2.10.2 Install cmake. The mysql 5.5 doesn’t use “./configure” command to configure and change to cmake, so we should install cmake. Check if there is cmake in your system with command as follows:

$ cmake -version

If there is no output as the following picture

you should install it by yourself:

$ sudo apt-get install cmake

2.10.3 Add new user group:

$ sudo groupadd mysql

2.10.4 Add new user:

$ sudo useradd mysql -g mysql

2.10.5 Create a new directory of database execution file :

$ sudo mkdir -p /usr/local/mysql

2.10.6 Create a new directory of new data file

$ sudo mkdir -p /db/mysql/data

2.10.8 Modify the directory owners:

$ sudo chown -R mysql:mysql /usr/local/mysql
$ sudo chown -R mysql:mysql /db/mysql/data
$ sudo chown -R mysql:mysql /usr/local/mysql/.
$ sudo chown -R mysql:mysql /db/mysql/data/.

2.10.8 Configure with cmake:

cmake \
-DCMAKE_INSTALL_PREFIX=/usr/local/mysql \
-DMYSQL_UNIX_ADDR=/usr/local/mysql/mysql.sock \
-DDEFAULT_CHARSET=utf8 \
-DDEFAULT_COLLATION=utf8_general_ci \
-DWITH_MYISAM_STORAGE_ENGINE=1 \
-DWITH_INNOBASE_STORAGE_ENGINE=1 \
-DWITH_ARCHIVE_STORAGE_ENGINE=1 \
-DWITH_BLACKHOLE_STORAGE_ENGINE=1 \
-DWITH_MEMORY_STORAGE_ENGINE=1 \
-DWITH_READLINE=1 \
-DENABLED_LOCAL_INFILE=1 \
-DMYSQL_DATADIR=/db/mysql/data \
-DMYSQL_USER=mysql \
-DMYSQL_TCP_PORT=3306

ERROR:CMake Error at cmake/readline.cmake:83 (MESSAGE):
Curses library not found. Please install appropriate package,

remove CMakeCache.txt and rerun cmake.On Debian/Ubuntu, package name is libncurses5-dev, on Redhat and derivates it is ncurses-devel.
Call Stack (most recent call first):
cmake/readline.cmake:126 (FIND_CURSES)
cmake/readline.cmake:193 (MYSQL_USE_BUNDLED_LIBEDIT)
CMakeLists.txt:325 (MYSQL_CHECK_READLINE)

Solution: according the prompt, install the missing package ncurses:

$ sudo apt-get install libncurses5-dev

adn then delete the cache files under current diretory:

$ sudo rm CMakeCache.txt

then reconfigure using cmake. Just copy commands above.

2.10.9 use the make command to compile the source file and generate the installation file:
$sudo make                                                      // compile

It shall take a long time to compile:

2.10.10 use command make install to install:
$ sudi make install                                              // install

2.10.11 copy the configuration file

$ sudo cp /usr/local/mysql/support-files/my-default.cnf /etc/my.cnf

2.10.12 enter the installation path:

$ cd /usr/local/mysql

2.10.13 run the configuration script;

$ sudo ./scripts/mysql_install_db –user=mysql –datadir=/db/mysql/data

2.10.14 copy the service start script:

$ sudo cp /usr/local/mysql/support-files/mysql.server /etc/init.d/mysql

2.10.15 start MySQL:

$ sudo service mysql start

2.10.16 set  password for root:

$ sudo /usr/local/mysql/bin/mysqladmin -u root password 123456

2.10.17 run on startup:

$ sudo update-rc.d mysql defaults

2.10.18 set mysql as system command:

$ sudo ln -s /usr/local/mysql/bin/* /bin/

after that, just execute the following command:

$ mysql -u root -p

you can login to mysql

2.10.19 set access permission

During installing MySQL, the application mysql_install_db installed the MySQL database authorization table. This table defines the initial accounts and authorizations of MySQL, and all accounts have no passwords. These accounts are super user accounts, they can perform any operations. Root account’s initial has no password, so anyone an use the root account without password to connect to MySQL server and get all permissions, which means MySQL installation is unprotected. If you want to prevent client form connecting without password, you should specify a password for anonymous account or delete anonymous account and set a password for MySQL users. Start MySQL client  console with “mysql –u root” to connect to MySQL server, command as follows:

$ mysql -u root -p

use the password set above (123456) to login, and perform:

mysql> DELETE FROM mysql.user WHERE Host=’localhost’ AND User=”;
Query OK, 1 rows affected (0.08 sec)
mysql> FLUSH PRIVILEGES;
Query OK, 1 rows affected (0.01 sec)

This means MySQL installed succeessfully~~

2.11 install the PHP

2.11.1 Download the file php-5.3.22.tar.gz on the above link or the official site, put it under /usr/local/src/, and extract it to php-5.3.22/, and enter the current directory. The commands as follows:
$ cd /usr/local/usr/            // enter the directory where the source code is
$ sudo tar zxvf  pcphp-5.3.22.tar.gz          // extract the file
$ cd php-5.3.22/                              // enter the current directory

2.11.2 Check and configure the installation environment with “configure” command, which will generate installation configuration file.  The command line as follows: ( for displaying explicitly, use “\” to split the command for several lines):

$ sudo ./configure \
> –prefix=/usr/local/php \                                                     // set the installation path for PHP5
> –with-config-file-path=/usr/local/php/etc \                     // specify the path saving PHP5 configuration files
> –with-apxs2=/usr/local/apache2/bin/apxs \                   // locate Apache2
> –with-mysql=/usr/local/mysql/ \                                      // specify the installation directory of PHP5
> –with-libxml-dir=/usr/local/libxml2/ \                             // locate libxml2
> –with-png-dir=/usr/local/libpng/ \                                   // locate libpng
> –with-jpeg-dir=/usr/local/jpeg6/ \                                    // locate jpeg
> –with-freetype-dir=/usr/local/freetype/ \                        // locate freetype
> –with-gd=/usr/local/gd2/ \                                                // locate gd
> –with-zlib-dir=/usr/local/zlib/ \                                         // locate zlib
> –with-mcrypt=/usr/local/libmcrypt/ \                              // locate libmcrypt
> –with-mysqli=/usr/local/mysql/bin/mysql_config \       // locate  MySQLi
> –enable-soap \                                                                    // enable SOAP
> –enable-mbstring=all \                                                       // enable multiple string
> –enable-sockets                                                                   // enable socket

2.11.3 use the make command to compile the source file and generate the installation file:
$make                                                      // compile
2.11.4 use command make install to install:
$ make install                                              // install
2.11.5 Create configuration file. Specify the location of configuration file by adding the option “–with-config-file-path=/usr/local/php/etc/” when using “configure” command to install the configuration. Copy the “php.ini- dist” file from the source directory to specified
directory “/usr/local/php/etc/” and change its name to “php.int”:

$ sudo cp php.ini-dist /usr/local/php/etc/php.ini      // create the configuration

2.11.6 Integrate Apache and PHP. Before compiling PHP, we add the option “–with-apxs2=/usr/local/apache2/bin/apxs” behind the configure command to make PHP as the Apache function. But we still need to modify Apache configuration file by adding PHP support to tell Apache certain extensions as PHP parse. For example, let Apache parse files with extensions like .php and .phtml to PHP. Open Apache configuration file /etc/httpd/httpd.conf, find the line “AddType application/x-gzip .gz .tgz” and under it add a command line “Addtype application/x-httpd- php .php .phtml”. Files with any extension can be parsed to PHP, as long as we add the type to the added command and separated with backspace, as following picture:

We add a line “AddType application/x-httpd-php-source .phps” in the end to take the file with .phps extensions as PHP source file for syntax highlighting.

2.11.7 Restart Apache server, for only after the restart changes of configuration file would take effect:

$ sudo /usr/local/apache2/bin/apachectl stop           // stop Apache service
$ sudo /usr/local/apache2/bin/apachectl start           // start Apache service

2.11.8 Test the PHP environment. Create a directory named phpinfo/ under /usr/local/apache2/htdocs and create a file named index.php. Add following lines to the file:

<?php
phpinfo();
?>

Open your browser enter the URL”http://localhost/phpinfo/index.php”, if the following picture occurs, it means your LAMP is successfully installed.

The function phpinfo() is to output most information about the PHP current status. It includes the information of compilation and extension, the PHP version, server information and environment, PHP environment, system information, path, local configuration value , HTTP header information and PHP License. Due to the different of each system’s installation, the  function phpinfo() can be used to check the configuration of a particular system and available predefined variable. It’s also a valuable debug tool, because it includes all EGPCS data(Environment,GET,POST,Cookie,Server).

large

ahaaaaaaaaaaaaaa~

Finally, we finished it

Sophia 译

Ubuntu下PHP扩展cURL

开发php的时候遇到一个错误,

Fatal error: Call to undefined function curl_init()

Google了一下,网上基本都是你抄我,我抄你,还不能解决,我勒个擦。还是自己动手吧,结合以前经验,解决方法如下:

0. 前提。我的php开发环境是用源码包编译、安装而成的。并且保留了php的源码包。

1. 安装cURL。
1.1 进入/usr/local/src目录,命令如下:
$ cd /usr/local/src

1.2 下载cURL源码包,可以通过命令下载,也可以直接去http://curl.haxx.se/download/选择版本下载,然后copy到该目录。如果是敲命令,如下:
$ sudo wget http://curl.haxx.se/download/curl-7.17.1.tar.gz

1.3 配置。在当前目录下执行命令:
$ sudo ./configure –prefix=/usr/local/curl

1.4 编译,命令如下:
$ sudo make

1.5 安装,命令如下:
$ sudo make install

如果安装成功以后,在/usr/local/curl/目录下将生成bin、include、lib和share四个目录。
Selection_135

2. 扩展php。
2.1 进入php源码包(不是安装以后的)位置/ext/curl/目录,我的在/usr/local/src/php-5.3.22/ext/curl,如下图所示Selection_134

2.2 在当前目录下,通过phpize可以建立php的外挂模块,命令如下:
$ sudo /usr/local/php/bin/phpize
其中/usr/local/php/是我的php安装路径,有可能与各位不一样。

2.3 配置扩展,命令如下:
$ sudo ./configure –with-php-config=/usr/local/php/bin/php-config –with-curl=/usr/local/curl

2.4 编译,命令如下:
$ sudo make

2.5 安装,命令如下:
$ sudo make install

安装成功后,会在/usr/local/php/lib/php/extensions目录下生成no-debug-zts-20090626(php版本不同,这个名称也许不同)目录,该目录下就能看到生成的curl.so文件,如下图所示。
Selection_136

2.6 修改php.ini配置文件,添加extension=”/usr/local/php/lib/php/extensions/no-debug-zts-20090626/curl.so”,如下图所示
Selection_137

2.7 重启apache服务器,完成。

Ubuntu搭建LAMP环境(jpeg-6b 安装错误 ,找不到libtool命令)

继续安装php开发环境,

jpeg-6b make的时候错误:

./libtool –mode=compile gcc -O2 -I. -c ./jcapimin.c
make: ./libtool: Command not found
make: *** [jcapimin.lo] Error 127

看提示应该是没有安装libtool,由于才拿到手里的服务器,什么都没装,出现这个错误也正常。

解决办法:安装libtool

1 在上面的链接或者网上下载 libtool-2.2.6a.tar.gz,放到/usr/local/src/目录下,解压软件包到当前目录libtool-2.2.6下,并进入libtool-2.2.6目录,命令如下:
$ cd /usr/local/usr/                                      // 进入源码包所在目录
$ sudo tar zxvf libtool-2.2.6a.tar.gz           // 解压缩
$ cd libtool-2.2.6                                         // 进入目录

2 使用“configure”命令检查并配置安装需要的系统环境,并生成安装配置文件,命令行如下:
$ ./configure
安装到默认路径就可以。

3 使用make命令编译源码文件并生成安装文件,命令如下:
$ sudo make                                                    // 编译

4 使用make install命令进行安装,命令如下:
$ sudo make install                                         // 安装

5 复制libtool中的config.sub和config.guess文件至jpeg-6b根目录,命令如下:
$ cd /usr/local/src/jpeg-6b/
$ sudo cp /usr/local/share/libtool/config/config.sub .
$ sudo cp /usr/local/share/libtool/config/config.guess .

6 重新配置并编译、安装jpeg-6b,命令如下:
$ sudo ./configure \
> –prefix=/usr/local/jpeg6/ \                             // 安装时将软件安装到/usr/local/jpeg6目录下
> –enable-shared \                                              // 建立共享库使用的GNU的libtool
> –enable-static                                                   // 建立静态库使用的GNU的libtool
$ sudo make                                                        // 编译
$ sudo make install                                             // 安装

7 Done.
————————————-华丽丽的分割线,下面是英语版———————–

English Version:

Continue to install the PHP environment.
An error occured when make jpeg-6b:

./libtool –mode=compile gcc -O2 -I. -c ./jcapimin.c
make: ./libtool: Command not found
make: *** [jcapimin.lo] Error 127

According the prompt, the libtool isn’t installed. It’s normal to have this error on a bare machine.

Solution: install libtool, of course!

1. Download the file libtool-2.2.6a.tar.gz on the above link or the official site, put it under /usr/local/src/, and extract it into libtool-2.2.6/ and then enter the current directory. The commands as follows:

$ cd /usr/local/usr/            // enter the directory where the source code is
$ sudo tar zxvf libtool-2.2.6a.tar.gz           // extract the file
$ cd libtool-2.2.6                              // enter the current directory

2. Check and configure the installation environment with “configure” command, which will generate installation configuration file.  The command line as follows:
$ ./configure
we can just install it in the default path.

3. use the make command to compile the source file and generate the installation file:
$make                                                      // compile

4. use command make install to install:
$ make install                                              // install

5. copy the config.sub and config.guess of libtool to jpeg-6b/, command as follows:
$ cd /usr/local/src/jpeg-6b/
$ sudo cp /usr/local/share/libtool/config/config.sub
$ sudo cp /usr/local/share/libtool/config/config.guess

6. reconfigure, compile and install jpeg-6b, commands as follows:
$ sudo ./configure \
> –prefix=/usr/local/jpeg6/ \                                   //install the software into /usr/local/jpeg6
> –enable-shared \                                       // GUN’s libtool will be used when creating shared lib
> –enable-static                                           // GUN’s libtool will be used when creating static  lib
$ sudo make                                                        // compile
$ sudo make install                                             // install

7. Done