ctime mtime atime

Unix/Linux系统文件有三个时间,ctime, mtime,atime。说说三个之间的区别。

ctime很多人以为是create time,创建时间。实际表示的是change time,改变时间。mtime是modify time,也可以翻译成改变时间。atime就是 access time。

st_atime

           Time when file data was last accessed. Changed by  the
following   functions:   creat(),   mknod(),   pipe(),
utime(2), and read(2).st_mtime
Time when data was last modified. Changed by the  fol-
lowing  functions:  creat(), mknod(), pipe(), utime(),
and write(2).

st_ctime
Time when file status was last changed. Changed by the
following   functions:   chmod(),   chown(),  creat(),
link(2),  mknod(),  pipe(),  unlink(2),  utime(),  and
write().

atime记录访问的时间,像创建读取或者执行的时候。
mtime随文件内容写入而改变。
ctime随文件读写入,改变文件名称,文件归属而改变。
chmod ctime修改,mtime不改。
cat atime修改。
ls -l 显示mtime
ls -lu 显示atime
ls -lc 显示ctime
参考链接:
1.http://www.cnblogs.com/ghgyj/p/3911621.html
2.http://www.cnblogs.com/oray/p/3786440.html

免费ssl证书

上次找到阿里云免费证书,但是只有一年期限。昨天由于公司网站迁移服务器,又找到了一款其他的免费https证书。名字叫letsencrypt,官网:https://letsencrypt.org。

官网推荐使用工具安装,工具网址:https://certbot.eff.org。

选择好服务器软件和服务器系统,以centos6和nginx为例。

1.wget https://dl.eff.org/certbot-auto

chmod a+x certbot-auto

下载certbot-auto文件,并增加可执行权限。

2.sudo ./path/to/certbot-auto –nginx。

运行certbot-auto需要root用户权限,后面跟参数–nginx,自动安装证书并修改nginx配置文件。如果只想安装证书,而手动修改nginx配置文件,–nignx参数后面加 certonly参数。

3 把生成的证书文件加载到nginx 对应的域名配置文件里面去,这个可以生成多个子域名的免费证书,阿里云免费证书只有一个域名。

4,免费的证书只有90天有效期,需要手动更新。更新命令sudo ./path/to/certbot-auto renew。这样就生成好了,如果只想测试下更新命令,后面加参数–dry-run。最后把更新命令加到crontab执行计划任务里面去。安装完毕。

最后,如果在安装证书第一步失败,提示nginx配置文件路径找不到,可以nginx安装路径参数,–nginx-server-root=/usr/local/nginx/conf。

官网网址:https://certbot.eff.org/lets-encrypt/centos6-nginx。

mysql count函数

mysql count函数,返回匹配行数是总数量。原型count(expr),有的人写count(*),也有人写count(column_name),比如count(id)。还是看官方手册怎么写的。

COUNT(*) is somewhat different in that it returns a count of the number of rows retrieved, whether or not they contain NULL values.

For MyISAM tables, COUNT(*) is optimized to return very quickly if the SELECT retrieves from one table, no other columns are retrieved, and there is no WHERE clause. For example:

SELECT COUNT(*) FROM student

 

count(*)有些不同,返回检索的行数,不管是否包含null值。对于MyISAM引擎,count(*)被优化成快速返回,如果select从一张表里接受值,没有其他的行数被检索,而且没有where条件。

意思就是对于MyISAM仅仅查询表的行数,不检索其他列,也没有where条件。count(*)是最快的返回方式。

 

This optimization only applies to MyISAM tables, because an exact row count is stored for this storage engine and can be accessed very quickly. COUNT(1) is only subject to the same optimization if the first column is defined as NOT
NULL
.

这种优化只针对MyISAM么表,因为具体的行数被存储引擎存储而且很容易快速访问。count(1) 仅仅在首列不被定义为不空时和count(*)相同。

COUNT(expr)

Returns a count of the number of non-NULL values of expr in the rows retrieved by a SELECT statement. The result is a BIGINT value.

If there are no matching rows, COUNT() returns 0.

返回表达式的值不为空的查询行数。

结论:count函数要针对不同的存储引擎来看。不带where条件的,用count(*)。带where条件的,受where条件限制。count(1)首列值不为空和count(*)同等效果。

 

session和cookie区别

老问题了,每次面试必问。还是引用wiki上面的解释吧。

session,wiki叫session id。session翻译中文就是会话,ssh登录unix系统,也是一个session。表示一种状态,一个概念。session id是对概念具体的实现。

In computer science, a session identifier, session ID or session token is a piece of data that is used in network communications (often over HTTP) to identify a session, a series of related message exchanges.

session id 是一块数据用在网络通信中,经常是HTTP通信中定义的一个状态,为了一系列的数据交换。https://en.wikipedia.org/wiki/Session_ID

cookie在wiki中定义是http cookie,表示是http协议中的一部分。

An HTTP cookie (also called web cookie, Internet cookie, browser cookie, or simply cookie) is a small piece of data sent from a website and stored on the user’s computer by the user’s web browser while the user is browsing.

http cookie也叫web cookie,互联网cookie ,浏览器cookie。是网站被用户浏览时,从网站发送过来并保存在用户电脑上面的一小段数据。

wiki:https://en.wikipedia.org/wiki/HTTP_cookie

wiki比较客观公正吧。

session是保存在服务器端的,而且持续时间也很短,一般只保存在用户浏览时段,浏览器关掉session也跟着清除掉,跟客户端的通信有两种方式,可以设置一个session cookie,跟着浏览器一起请求过来,也可以把session放在url上当做参数一起请求过来,大多数采用session  cookie这种方式。PHP生成session之后,有个PHPSESSID的cookie。

cookie是保存在客户端上面的一段数据,持续时间也比较长些。

php json_decode返回null

给app写一个接口,返回数据格式为json。自己本地写curl模拟请求,把结果json_decode解析下,本以为会返回数据,结果返回一个null。拼接好参数浏览器里面请求,返回的又是乍看一个正常的json格式字符串。编码也是UTF-8,也把多余的空行删掉了,但是还是返回的null。又回到浏览器那串字符串上面找问题。

乍看是一个json格式字符串,但是复制到bejson网站解析时,确多了个红点。F12查看下网络,字符串前面多了个&#65279。搜索下这个词,出现很多页面,看了下大概明白了什么原因,文件里面多了BOM头。

BOM(Byte order mark),字面意思是字节顺序标记,都知道计算机有大端小端顺序争论,甚至不惜发动战争。wiki原文引用:

The byte order mark (BOM) is a Unicode character, U+FEFF byte order mark (BOM), whose appearance as a magic number at the start of a text stream can signal several things to a program consuming the text

在文本流前面作为一个幻数,可以向使用文本的程序发出几个信号。三个字节16进制表示问0xEF,0xBB,0xBF。

网上也提供了很多方法,用编辑器保存为utf-8无bom的。我也都试过了,也都没改过来。最后写个函数处理掉的。

function removeBom($str){

if(!empty($str)){

$c1 = substr(0,1);

$c1 = substr(1,1);

$c1 = substr(2,1);

if(ord($c1) == 239 && ord($c2) == 187 && ord($c3) == 191){

return substr($str,3);

}

}

}

bom头还有个危害就是session和cookie也都用不了了,在编码的时候编辑器保存文件还是要选择utf8无bom格式。

把带有bom的返回结果用函数清楚下,问题就解决了。虽然很慢,但是没放弃前进。

thinkphp5分析一

thinkphp在十年周的时候,发布了新的版本thinkphp5。官方如下介绍:

ThinkPHP5.0版本是一个颠覆和重构版本,采用全新的架构思想,引入了更多的PHP新特性,优化了核心,减少了依赖,实现了真正的惰性加载,支持composer,并针对API开发做了大量的优化,包括路由、日志、异常、模型、数据库、模板引擎和验证等模块都已经重构,不适合原有3.2项目的升级,请慎重考虑商业项目升级,但绝对是新项目的首选(无论是WEB还是API开发)。

废话不说,一看详细。

下载的版本是5.0.16完整版,先看目录结构。

目录结构和版本3有几个不同的地方,支持composer,多了composer.json文件,composer确实是趋势,yii2版本也加入了composer支持。多了build.php文件,多了extend vendor两个目录。原来的think.php也以unix shell脚本文件的形式写的,下图源码。

但是这样一来,windows服务器怎么识别这个think文件,跟unix服务器不太一样。

extends看名字应该是放扩展,暂时是空的,跳过。

vendor目录包含composer的自动加载文件,文件,命名空间,类,psr4标准。topthink目录是原来版本3的几个类库,单独拿出来了。

下面看主目录。

绿色背景是tp5目录,黑色背景是tp3目录。文件命名分格变了,去掉了.class后缀文件名短了。5的目录多了console.php和console目录,这个是新的主入口文件Loader.php主要是加载类文件,增加了request和response两个类。所有的请求都在request类里面,相当于版本3dispatcher类的作用。定义了get,post方法。

5增加了自定义路由,也是重写了Route类的后果,后面单独写。知道Route类里面包含解析之后的module,controller,action动作。

start.php只有两行代码,包含base.php,然后就执行App:run()->send()。

APP类分析:

可以看到App里面有几个方法,其中有3个invoke开头的反射函数,把版本3里面的exec函数拆分成3个invoke函数。checkRoute方法和route方法还和以前一样,返回module,controller,action,最后通过反射去执行。

Model在版本5这个变化比较大,版本3model直接提供数据库操作方法。initialize函数初始化,没有连接数据库,就是官方说的懒链接,需要数据库才连接数据库。并且拆分为connection builder query三个类,这个也是和laravel框架一样了。

总结,thinkphp版本5支持composer,model也设计了懒连接,需要数据库才连接。都是随着技术趋势在进步,不忘初心。希望tp框架越走越远,越来越好。

 

 

 

 

 

thinkphp3.2分析三

现在说说thinkphp框架里面其他的工具类和实际的项目应用。

软甲开发都遵循MVC分层模式。M对应的是model,模型的意思,提供数据处理的功能,V对应view,视图层,主要提供面向终端用户展示的功能。C对应control,控制层,提供流程控制的功能。所有的业务流程控制都在控制层完成,是连接模型和视图层的枢纽,获取模型层的数据,然后传入视图层去完成展示。

thinkphp框架类里面也看到,controller类,model类,和template类。

controller类除了几个魔术方法,有提供了ajax返回,创建静态页面方法和display方法,display  show fetch都是调用view类里面对应的方法。view就是view类的实例。

model类里面很多方法,用于获取数据库的数据,thinkphp3.2里面的model直接和数据库连接,不支持ORM那种数据对象映射模型。

在model类构造方法时,db方法提供了数据库类实例化,保存数据库连接。

可以看到,数据库实例化是根据不同的配置,不同的配置选项返回一个不同的实例。有的项目需要数据库读写分离,这样就可以有不同的链接实例,只需要改动配置文件就可以,很方便。

model类里面提供了原生的execute和query方法,也有面向对象的new model()->where()->select()这种,用户手册里面有详细介绍。

thinkphp在view层中开启了模板引擎,默认用的smarty模板,view类基本也是对smarty类的重新封装。

还有几个其他的工具类,从文件名能够分别是起什么作用的。

auth是一个提供权限认证类,基于权限表。

behavior是行为基类,只提供一个run方法。

build类是初始化项目构建App下面的目录。

每个目录对应的名字都很清晰明了,里面多了个service目录,service里面包含一些服务类。在业务中碰到一些常用的操作,两个不同的控制器都需要调用,但是不是所有的控制器都需要,写在控制基类让所有控制类继承也不合适。类似php语法里面的trait功能,可以单独拿出来用的。不限制于在控制层,如果模型层有需要也可以调用。

后面还有缓存类,和数据库一样,提供不同的driver type。默认的有memcache,redis,apc,wincache,xcache。加密类提供的driver type有base64,think自带的。图像处理提供的driver type有gd库和imagick。session处理类,提供的driver type有db和memcache。日志类,文件上传类,显示分页类,verify是验证码类。还有跟Think目录同级的目录,也都是第三方或者其他内置的类库。这样所有的文件基本都过一遍了。

总结:thinkphp发展至今已有十几年的时间了。版本5是近两年才出现的,之前一直都是版本3。经过这么多年的发展而没有停止,仍然在国内占据了很多市场。个人感觉最关键的地方就是直观,没有绕的地方。满足大部分中小企业开发的需求,上手快速,学习成本低。缺点就是跟不上技术发展,近几年composer的出现,提供了很多的第三方类库包,但是开发组已经意识到了这个问题,开发出了版本5。声明说和3完全不一样的版本,支持composer,为了和laravel竞争吧应该是。后面了解了再分享。

thinkphp3.2分析二

Thinkphp.class.php::start();运行项目。

Thinkphp类包含两个私有属相,$_instance,$_map,10个公共静态方法。

start方法:

注册自动加载方法:autoload方法。

  1. // 注册AUTOLOAD方法
    spl_autoload_register(‘Think\Think::autoload’);

设定错误和异常处理

// 设定错误和异常处理
register_shutdown_function(‘Think\Think::fatalError’);
set_error_handler(‘Think\Think::appError’);
set_exception_handler(‘Think\Think::appException’);

// 初始化文件存储方式
Storage::connect(STORAGE_TYPE);

$runtimefile = RUNTIME_PATH.APP_MODE.’~runtime.php’;
if(!APP_DEBUG && Storage::has($runtimefile)){
Storage::load($runtimefile);
}else{
if(Storage::has($runtimefile))
Storage::unlink($runtimefile);
$content = ”;
// 读取应用模式
$mode = include is_file(CONF_PATH.’core.php’)?CONF_PATH.’core.php’: MODE_PATH .APP_MODE.’.php’;
// 加载核心文件
foreach ($mode[‘core’] as $file){
if(is_file($file)) {
include $file;
if(!APP_DEBUG) $content .= compile($file);
}
}

// 加载应用模式配置文件
foreach ($mode[‘config’] as $key=>$file){
is_numeric($key)?C(load_config($file)):C($key,load_config($file));
}

// 读取当前应用模式对应的配置文件
if(‘common’ != APP_MODE && is_file(CONF_PATH.’config_’.APP_MODE.CONF_EXT))
C(load_config(CONF_PATH.’config_’.APP_MODE.CONF_EXT));

// 加载模式别名定义
if(isset($mode[‘alias’])){
self::addMap(is_array($mode[‘alias’])?$mode[‘alias’]:include $mode[‘alias’]);
}

// 加载应用别名定义文件
if(is_file(CONF_PATH.’alias.php’))
self::addMap(include CONF_PATH.’alias.php’);

// 加载模式行为定义
if(isset($mode[‘tags’])) {
Hook::import(is_array($mode[‘tags’])?$mode[‘tags’]:include $mode[‘tags’]);
}

// 加载应用行为定义
if(is_file(CONF_PATH.’tags.php’))
// 允许应用增加开发模式配置定义
Hook::import(include CONF_PATH.’tags.php’);

// 加载框架底层语言包
L(include THINK_PATH.’Lang/’.strtolower(C(‘DEFAULT_LANG’)).’.php’);

if(!APP_DEBUG){
$content .= “\nnamespace { Think\\Think::addMap(“.var_export(self::$_map,true).”);”;
$content .= “\nL(“.var_export(L(),true).”);\nC(“.var_export(C(),true).’);Think\Hook::import(‘.var_export(Hook::get(),true).’);}’;
Storage::put($runtimefile,strip_whitespace(‘<?php ‘.$content));
}else{
// 调试模式加载系统默认的配置文件
C(include THINK_PATH.’Conf/debug.php’);
// 读取应用调试配置文件
if(is_file(CONF_PATH.’debug’.CONF_EXT))
C(include CONF_PATH.’debug’.CONF_EXT);
}
}

// 读取当前应用状态对应的配置文件
if(APP_STATUS && is_file(CONF_PATH.APP_STATUS.CONF_EXT))
C(include CONF_PATH.APP_STATUS.CONF_EXT);

// 设置系统时区
date_default_timezone_set(C(‘DEFAULT_TIMEZONE’));

// 检查应用目录结构 如果不存在则自动创建
if(C(‘CHECK_APP_DIR’)) {
$module = defined(‘BIND_MODULE’) ? BIND_MODULE : C(‘DEFAULT_MODULE’);
if(!is_dir(APP_PATH.$module) || !is_dir(LOG_PATH)){
// 检测应用目录结构
Build::checkDir($module);
}
}

// 记录加载文件时间
G(‘loadTime’);
// 运行应用
App::run();

 

App对应的是Thinkphp.class.php同目录下面的App.class.php。

run方法:

可以看到run方法调用了init和exec方法。

 

init方法就是调用Dispatcher::dispatch()方法。

 

Dispatcher类在Dispatcher.class.php里面,有5个静态方法,除了dispatch方法,其他四个都是私有方法,主要是获取url参数,获取moduel,control,action这些参数.

在dispatch方法里面,调用了Route::check()方法。

Route类在Route.class.php中,是一个路由类。

 

除了check方法是公开,其他都是私有方法。

经过这些转换,终于到了App::exec()方法了。

最核心的一句,$method = new \ReflectionMethod($module,$action),如果方法是公共并且不是静态方法,检测是否有_before_方法,有的话并且是公共,执行before方法。

检测方法是否有参数,有参数invokeArgs,没有直接invoke。如果有after方法,调用after方法。如果异常或者方法调用异常,调用__call魔术方法。至此,整个运行流程完毕。

 

 

 

 

thinkphp3.2分析一

thinkphp是一个国产PHP框架,官方网站为www.thinkphp.cn。thinkPHP分两个大版本,版本3和版本5。以下介绍的是3.2版本。

上图是一般项目的目录分布,index.php是入口文件。

检测环境,如果PHP的版本是5.3以下就终止执行。3.2版本里面用到了命名空间,PHP5.3版本以上才支持命名空间。是否debug模式,生产环境设置为false,开发环境设置成true。剩下的就是几个默认目录,定义好之后建立相应的目录就可以。最后一行,包含thinPHP的主文件。

以下是ThinkPHP/ThinkPHP.php文件内容。

// 记录开始运行时间
$GLOBALS[‘_beginTime’] = microtime(TRUE);
// 记录内存初始使用
define(‘MEMORY_LIMIT_ON’,function_exists(‘memory_get_usage’));
if(MEMORY_LIMIT_ON) $GLOBALS[‘_startUseMems’] = memory_get_usage();

// 版本信息
const THINK_VERSION = ‘3.2.3’;

// URL 模式定义
const URL_COMMON = 0; //普通模式
const URL_PATHINFO = 1; //PATHINFO模式
const URL_REWRITE = 2; //REWRITE模式
const URL_COMPAT = 3; // 兼容模式

// 类文件后缀
const EXT = ‘.class.php’;

这几行都是容易理解,有注释。继续往下看。

// 系统常量定义
defined(‘THINK_PATH’) or define(‘THINK_PATH’, __DIR__.’/’);
defined(‘APP_PATH’) or define(‘APP_PATH’,dirname($_SERVER[‘SCRIPT_FILENAME’]).’/’);
defined(‘APP_STATUS’) or define(‘APP_STATUS’, ”); // 应用状态 加载对应的配置文件
defined(‘APP_DEBUG’) or define(‘APP_DEBUG’, false); // 是否调试模式

这几行也好理解,定义系统的路径常亮。

if(function_exists(‘saeAutoLoader’)){// 自动识别SAE环境
defined(‘APP_MODE’) or define(‘APP_MODE’, ‘sae’);
defined(‘STORAGE_TYPE’) or define(‘STORAGE_TYPE’, ‘Sae’);
}else{
defined(‘APP_MODE’) or define(‘APP_MODE’, ‘common’); // 应用模式 默认为普通

一般都是普通模式,sae模式是新浪sae云,合作厂商?

模式
defined(‘STORAGE_TYPE’) or define(‘STORAGE_TYPE’, ‘File’); // 存储类型 默认为File
}

defined(‘RUNTIME_PATH’) or define(‘RUNTIME_PATH’, APP_PATH.’Runtime/’); // 系统运行时目录
defined(‘LIB_PATH’) or define(‘LIB_PATH’, realpath(THINK_PATH.’Library’).’/’); // 系统核心类库目录
defined(‘CORE_PATH’) or define(‘CORE_PATH’, LIB_PATH.’Think/’); // Think类库目录
defined(‘BEHAVIOR_PATH’)or define(‘BEHAVIOR_PATH’, LIB_PATH.’Behavior/’); // 行为类库目录
defined(‘MODE_PATH’) or define(‘MODE_PATH’, THINK_PATH.’Mode/’); // 系统应用模式目录
defined(‘VENDOR_PATH’) or define(‘VENDOR_PATH’, LIB_PATH.’Vendor/’); // 第三方类库目录
defined(‘COMMON_PATH’) or define(‘COMMON_PATH’, APP_PATH.’Common/’); // 应用公共目录
defined(‘CONF_PATH’) or define(‘CONF_PATH’, COMMON_PATH.’Conf/’); // 应用配置目录
defined(‘LANG_PATH’) or define(‘LANG_PATH’, COMMON_PATH.’Lang/’); // 应用语言目录
defined(‘HTML_PATH’) or define(‘HTML_PATH’, APP_PATH.’Html/’); // 应用静态目录
defined(‘LOG_PATH’) or define(‘LOG_PATH’, RUNTIME_PATH.’Logs/’); // 应用日志目录
defined(‘TEMP_PATH’) or define(‘TEMP_PATH’, RUNTIME_PATH.’Temp/’); // 应用缓存目录
defined(‘DATA_PATH’) or define(‘DATA_PATH’, RUNTIME_PATH.’Data/’); // 应用数据目录
defined(‘CACHE_PATH’) or define(‘CACHE_PATH’, RUNTIME_PATH.’Cache/’); // 应用模板缓存目录
defined(‘CONF_EXT’) or define(‘CONF_EXT’, ‘.php’); // 配置文件后缀
defined(‘CONF_PARSE’) or define(‘CONF_PARSE’, ”); // 配置文件解析方法
defined(‘ADDON_PATH’) or define(‘ADDON_PATH’, APP_PATH.’Addon’);

以上代码定义了think类库目录,第三方类库目录,应用公共目录,应用配置目录。在runtime目录里面定义了四个目录,日志目录,缓存目录,数据目录,以及模板缓存目录。最后定义了文件后缀常亮,猜测是历史原因,在php5之前,有php3,php4版本,后缀名带有数字,现在都是纯粹的.php结尾。

// 系统信息
if(version_compare(PHP_VERSION,’5.4.0′,'<‘)) {
ini_set(‘magic_quotes_runtime’,0);
define(‘MAGIC_QUOTES_GPC’,get_magic_quotes_gpc()? true : false);
}else{
define(‘MAGIC_QUOTES_GPC’,false);
}

PHP版本小于5.4关闭魔术引用模式,5.4版本及以上已移除。

define(‘IS_CGI’,(0 === strpos(PHP_SAPI,’cgi’) || false !== strpos(PHP_SAPI,’fcgi’)) ? 1 : 0 );
define(‘IS_WIN’,strstr(PHP_OS, ‘WIN’) ? 1 : 0 );
define(‘IS_CLI’,PHP_SAPI==’cli’? 1 : 0);

if(!IS_CLI) {
// 当前文件名
if(!defined(‘_PHP_FILE_’)) {
if(IS_CGI) {
//CGI/FASTCGI模式下
$_temp = explode(‘.php’,$_SERVER[‘PHP_SELF’]);
define(‘_PHP_FILE_’, rtrim(str_replace($_SERVER[‘HTTP_HOST’],”,$_temp[0].’.php’),’/’));
}else {
define(‘_PHP_FILE_’, rtrim($_SERVER[‘SCRIPT_NAME’],’/’));
}
}

不同的SAPI模式下面的定义常量 _PHP_FILE_
if(!defined(‘__ROOT__’)) {
$_root = rtrim(dirname(_PHP_FILE_),’/’);
define(‘__ROOT__’, (($_root==’/’ || $_root==’\\’)?”:$_root));
}

定义__ROOT__常量。

}

// 加载核心Think类
require CORE_PATH.’Think’.EXT; //Thinkphp/Library/Think/Think.class.php
// 应用初始化
Think\Think::start();

 

以上是ThinkPHP/ThinkPHP.php全部内容。

 

 

PHP扩展安装APC

Alternative PHP Cache (APC) 是一个开放自由的 PHP opcode 缓存。但是手册上已经提示该扩展在考虑停止维护并且死亡,建议用APCU(APC user cache)替代。APCU项目地址是https://github.com/krakjoe/apcu。

APCu is an in-memory key-value store for PHP. Keys are of type string and values can be any PHP variables.APCu only supports userland caching of variables.APCu is APC stripped of opcode caching.

APCu是PHP的一个key-value在内存里面的存储系统。keys可以是string类型,values可以是任何类型的PHP变量。APCu仅仅支持用户区的变量缓存。APCu是从操作码缓存剥离的APC。

安装开始了,先把源码下载下来,wget https://github.com/krakjoe/apcu/archive/PHP5.zip。自己机器是macOS 10版本的,PHP5.6版本,Apache2.4版本。以下都是在终端执行的命令。

unzip PHP5.zip

cd apcu-PHP5

phpize

./configure

make

make install

成功执行到这步就算安装完成了,在modules目录下生成了apcu.so的文件。make install 命令其实就是把 ./modules/apcu.so复制到扩展目录。我的扩展目录是/usr/lib/php/extensions/no-debug-non-zts-20131226/,然后用sudo命令从cofigure命令开始重新执行了一遍,还是提示权限不足 ,放弃了。

最后修改php.ini,加上一行extension=/your/path/apcu.so。

重启Apache,运行phpinfo函数页面。

安装完毕。

本来就这样结束了,想想又不甘心,在服务器上又执行了一遍,但是服务器确安装成功,没有提示权限不足。服务器的扩展目录是/usr/lib64/php。

网上搜了下,也有其他人遇到macOS权限不足的问题,猜测macOS虽然是基于unix系统,但是目标用户和windows一样的普通用户,为了防止用破坏系统而故意设置成权限不允许,即使是sudo也不允许。