Jimmygao 发布的文章

首先恭喜typecho v1.0的上线!

其次,这篇文章同thinkphp的源代码解析一样都是老高谋划了很久的文章,国庆节由于单位加班没有时间写,今天终于等来了轮休,果断放开了写。希望大家多多支持!

最后老高想说的是,如果大家有兴趣研究源码,那么问题来了,如何高效的学习研究源代码?

老高的建议是:

  1. 一定要熟悉MVC模式(针对WEB开发)
  2. 先看看文档再动手
  3. 分辨什么是好的坏的代码,不要搞盲目崇拜
  4. 做笔记

以下:

文档

如果有什么不明白的,文档里也许会找到答案。

typecho开发文档

版本

再研究源代码前,如果知道自己使用的typecho的版本呢?

答案写在var/Typecho/Common.php里,Typecho_Common类中的常量VERSION

例子:

class Typecho_Common
{
    /** 程序版本 */
    const VERSION = '1.0/14.10.9';
    ...
}

开启DEBUG模式

有些同学可能已经发现,typecho默认对外隐藏了PHP的错误信息,如果我们想要看到真正的报错信息,需要开启typecho的DEBUG模式,也可以叫做开发模式。当我们开启了这个模式后,在开发插件或者了解系统原理的时候就能够得到可视化的错误信息了。

开启方法:

# 修改/config.inc.php
# 在代码的第一行加入
/**开启debug模式*/
define('__TYPECHO_DEBUG__',1);

ps.调试的时候如果你的服务器没有安装xdebug,那么你的var_dump()信息会没有格式。

在此老高推荐使用TP框架内的方法dump(),以后我们就可以使用dump()打印变量信息了。

# 修改/config.inc.php
# 在debug后加入

/**
 * 浏览器友好的变量输出
 * @param mixed $var 变量
 * @param boolean $echo 是否输出 默认为True 如果为false 则返回输出字符串
 * @param string $label 标签 默认为空
 * @param boolean $strict 是否严谨 默认为true
 * @return void|string
 */
function dump($var, $echo=true, $label=null, $strict=true) {
    $label = ($label === null) ? '' : rtrim($label) . ' ';
    if (!$strict) {
        if (ini_get('html_errors')) {
            $output = print_r($var, true);
            $output = '
' . $label . htmlspecialchars($output, ENT_QUOTES) . '
'; } else { $output = $label . print_r($var, true); } } else { ob_start(); var_dump($var); $output = ob_get_clean(); if (!extension_loaded('xdebug')) { $output = preg_replace('/\]\=\>\n(\s+)/m', '] => ', $output); $output = '
' . $label . htmlspecialchars($output, ENT_QUOTES) . '
'; } } if ($echo) { echo($output); return null; }else return $output; }

入口

入口文件为index.php,国际惯例贴代码。

if (!@include_once 'config.inc.php') {
    file_exists('./install.php') ? header('Location: install.php') : print('Missing Config File');
    exit;
}

/** 初始化组件 */
Typecho_Widget::widget('Widget_Init');

/** 注册一个初始化插件 */
Typecho_Plugin::factory('index.php')->begin();

/** 开始路由分发 */
Typecho_Router::dispatch();

/** 注册一个结束插件 */
Typecho_Plugin::factory('index.php')->end();

typecho也采用了流行的单一入口,在此会引出一个伪静态的问题,此处先留个坑,以后补上。

index.php文件流程:

config.inc.php文件如果存在,就引入;如果不存在,就跳转到install.php进行程序安装,请原谅老高在此跳过install.php流程,如果读者有问题,请留言交流。

config.inc.php在安装程序的时候会自动生成,其主要工作是:引入程序常量,设定包含路径,引入各个核心文件(注意此时没有使用__autoLoad,所以只能require),执行Typecho_Common::init()初始化工作,保存数据库连接信息并初始化数据库对象。

Typecho_Common::init()位于var/Typecho/Common.php,方法代码:

public static function init()
    {
        ini_set( 'display_errors', 'On' );
        /** 设置自动载入函数 */
        if (function_exists('spl_autoload_register')) {
            spl_autoload_register(array('Typecho_Common', '__autoLoad'));
        } else {
            function __autoLoad($className) {
                Typecho_Common::__autoLoad($className);
            }
        }

        /** 兼容php6 */
        if (function_exists('get_magic_quotes_gpc') && get_magic_quotes_gpc()) {
            $_GET = self::stripslashesDeep($_GET);
            $_POST = self::stripslashesDeep($_POST);
            $_COOKIE = self::stripslashesDeep($_COOKIE);

            reset($_GET);
            reset($_POST);
            reset($_COOKIE);
        }

        /** 设置异常截获函数 */
        set_exception_handler(array('Typecho_Common', 'exceptionHandle'));
    }

代码中ini_set( 'display_errors', 'On' );是老高自己加的,便于debug,请无视。此方法的主要工作是注册autoload,如果系统打开了magic_quotes_gpc,就使用stripslashesDeep处理输入数据,去除系统自动加入的/,最后接管了系统的异常截获。

config.inc.php完成使命后,控制权又回到了index.php文件。

紧接着执行了Typecho_Widget::widget('Widget_Init'),Typecho_Widget哪里来的?请研究一下init阶段的autoload方法,把类名中的_\替换为/,最后加上.php,这样类名就被映射到了一个确定的文件了。以Typecho_Widget为例,系统将得到Typecho/Widget.php,由于系统核心文件都在var下,那么最终的路径即var/Typecho/Widget.php。所以我们就得到了这样的规律,类名被_分开,类一般会以Typecho或Widget开头,分别对应着文件夹Typecho或Widget,之后就根据剩下的片段去找最终的文件名即可!

@include_once str_replace(array('\\', '_'), '/', $className) . '.php';

Widget类是整个系统的核心类(抽象类),他抽象出了几个很不错的功能,这一点Widget内部方法与接口有介绍,需要注意的是魔术方法__get会在保护属性$row里查找变量,$row也让Widget类增色不少,__callpush方法也需要留意。

下面介绍的是Typecho_Widget::widget方法,widget方法其实是一个工厂方法,他接受一个类名,初始化输入输出对象,一并传入目标类名,执行了目标类的构造方法和execute方法,并将实例化的类保存在self::$_widgetPool数组中。execute十分重要,在thinkphp中有一个异曲同工的方法,叫_initalize,位于controller父类中。

以index.php文件中Typecho_Widget::widget('Widget_Init')为例,Typecho_Widget的widget接收到'Widget_Init',初始化var/Widget/Init.php中的Widget_Init类后,执行了其execute方法。该方法又调用了$this->widget('Widget_Options'),即自己又初始化了Widget_Options类,Widget_Options类读出了user = 0的所有系统配置,并将Widget_Options保存在局部变量$options里,进行了一系列的初始化工作。值得留意的地方:

# $options包含了路由信息
# 系统在这一步才执行了解析PathInfo动作
$this->request->getPathInfo();
# 路由器在此初始化
Typecho_Router::setRoutes
# 所有插件在此初始化
Typecho_Plugin::init($options->plugins);
# 下面还有初始化回执,设定了返回的编码和类型
$this->response->setCharset($options->charset);
$this->response->setContentType($options->contentType);
# 时区设置还有session初始化
# 最后打开缓冲

至此Typecho_Widget::widget('Widget_Init')执行完毕!这时系统初始化正式完毕,开始真正的'工作'!

2015年01月12日更新:

开启开发者模式

下一节

码字不易,转载请注明出处。

spl_autoload_register、set_exception_handler和set_error_handler、get_include_path等。

spl_autoload_register

__autoload函数一样,但是更灵活。他的功能是当程序找不到当前正在使用的类时,在报错前,会调用此函数,如果找到了,就继续工作。

set_exception_handler

接管了原本的异常处理,可以隐藏或者美化输出,可以用throw new Exception触发。

set_error_handler

同上,接管了错误处理。可以用trigger_error触发。

镜像下载

centos官方 Aliyun Open Source Mirror Site 网易开源镜像站

虚拟化工具

免费的virtualbox,下载地址 KVM Xen

安装

记一次centos最小安装 centos7.0 的最小化安装

优化

分享一个centos6.*优化脚本 CentOS精简命令

后续

关闭防火墙和SELinux

# 关闭防火墙
service iptables stop 
chkconfig iptables off
chkconfig ip6tables off
# SELinux
vi /etc/selinux/config
# change
SELINUX=disabled
#网卡
------
vi /etc/sysconfig/network-scripts/ifcfg-eth0
TYPE=Ethernet
# change
ONBOOT=yes
NM_CONTROLLED=yes
# change
BOOTPROTO=dhcp
or
BOOTPROTO=static
# 加上
# 静态IP
IPADDR=192.168.1.107
# 设置子网
NETMASK=255.255.255.0
# 设置网关
GATEWAY=192.168.1.1
# 设置DNS
DNS1=114.114.114.114
IPV6INIT=no
USERCTL=no
------
service network restart
chkconfig network on
------
# 全局关闭IPv6
vi /etc/sysctl.conf
#加上
net.ipv6.conf.all.disable_ipv6 = 1
net.ipv6.conf.default.disable_ipv6 = 1
------
sysctl -p
reboot

crontab

yum install -y vixie-cron
yum install -y crontabs
service crond start

MySQL

yum install -y mysql-server
mysql_db_install
mysql_secure_installation
service mysqld start

ntpdate

yum install -y ntpdate rdate
ntpdate 210.72.145.44

nginx

nginx配置详解

PHP

编译PHP5.6

# 慎用
yum install -y zabbix zabbix-get zabbix-server zabbix-web-mysql zabbix-web zabbix-agent 

打开错误:

ini_set( 'display_errors', 'On' );

这篇文章于昨日早在215路早读时看到,写的很不错!可以作为学习框架或者写自己的框架之前的读物。

ps.文章中提到了一个名词——控制反转。这个词可能经常会考倒刚入门程序员。控制反转其实其实是一种外包的思想,将总做交给各个领域的'专家'去做,而你只负责如何调度他们的工作。明确的分工会给系统带来很多维护上的便利。这个概念常常和依赖注入同时出现,而什么是依赖注入呢?其实他是控制反转的一个实现方式。

如果你对框架这个概念还不是很理解,那么还可以参考一下老高的系列文章THINKPHP框架解析,老高带你深入框架内部,去看看框架到底做了什么,和为什么这么做。希望这篇转帖和老高的文章能够帮助你深入理解框架的作用。

阅读剩余部分

编译安装nginx后,没有将nginx配置为服务,则无法使用诸如service nginx restart的命令,下面我们看看如何将其配置为服务。

编写脚本

vi /etc/init.d/nginx

写入以下内容,并修改nginx路径

#!/bin/sh   
#   
# nginx - this script starts and stops the nginx daemon   
#   
# chkconfig: - 85 15   
# description: Nginx is an HTTP(S) server, HTTP(S) reverse   
# proxy and IMAP/POP3 proxy server   
# processname: nginx   
# chkconfig: 2345 90 91   
# description: nginx web server  
# processname: nginx  
# config: /opt/nginx/conf/nginx.conf  
# pidfile: /opt/nginx/nginx.pid  
  
# Source function library.  
. /etc/init.d/functions  
  
# Source networking configuration.  
. /etc/sysconfig/network  
  
  
if [ -f /etc/sysconfig/nginx ];then  
. /etc/sysconfig/nginx  
fi  
  
# Check that networking is up.   
[ "$NETWORKING" = "no" ] && exit 0  
  
nginx="#改为nginx二进制的路径"   
prog=$(basename $nginx)  
  
NGINX_CONF_FILE="/etc/nginx/nginx.conf"  
  
[ -f /etc/sysconfig/nginx ] && . /etc/sysconfig/nginx  
  
lockfile=/var/lock/subsys/nginx  
  
start() {   
[ -x $nginx ] || exit 5   
[ -f $NGINX_CONF_FILE ] || exit 6   
echo -n $"Starting $prog: "   
daemon $nginx #-c $NGINX_CONF_FILE   
retval=$?   
echo   
[ $retval -eq 0 ] && touch $lockfile   
return $retval   
}  
  
stop() {   
echo -n $"Stopping $prog: "   
killproc $prog -QUIT   
retval=$?   
echo   
[ $retval -eq 0 ] && rm -f $lockfile   
return $retval   
killall -9 nginx   
}  
  
restart() {   
configtest || return $?   
stop   
sleep 1   
start   
}  
  
reload() {   
configtest || return $?   
echo -n $"Reloading $prog: "   
killproc $nginx -HUP   
RETVAL=$?   
echo   
}  
  
force_reload() {   
restart   
}  
  
configtest() {   
$nginx -t #-c $NGINX_CONF_FILE   
}  
  
rh_status() {   
status $prog   
}  
  
rh_status_q() {   
rh_status >/dev/null 2>&1   
}  
  
case "$1" in   
start)   
    rh_status_q && exit 0   
    $1   
    ;;   
stop)   
rh_status_q || exit 0   
    $1   
    ;;   
restart)   
    $1   
    ;;   
test)   
    configtest   
    ;;   
reload)   
    rh_status_q || exit 7   
    $1   
    ;;   
force-reload)   
    force_reload   
    ;;   
status)   
    rh_status   
    ;;   
condrestart|try-restart)   
    rh_status_q || exit 0   
    ;;   
*)   
echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload|test}"   
exit 2   
esac

给予执行权

chmod a+x /etc/init.d/nginx

添加并打开服务

chkconfig --add nginx
chkconfig nginx on

测试

service nginx start
service nginx stop 
service nginx reload

转自:

http://binyan17.iteye.com/blog/1688308

自从使用mac以后,ssh连接总是超时成了老高的一个心病啊,只要一小会儿不动电脑,远程就失去相应,或者干脆直接提示broken pipe,然后断掉。现在终于有了算是能接受的解决办法。

方法一:直截了当砍掉法

~.,是的,你没有看错!这个组合命令就是主动断开ssh的命令,不行自己问问man。

方法二:修改配置文件

服务器和客户端每隔一定的时间会发一个KeepAlive请求,避免因为路由器或线路的限制而断线,例子中的60s可以因具体的环境改变。

针对服务器端

修改/etc/ssh/sshd_config,修改ServerAliveInterval一项,而ServerAliveCountMax表示如果失败重试的次数

ServerAliveInterval 60
ServerAliveCountMax 3

针对客户端

vi /etc/ssh_config
ClientAliveInterval 60
ClientAliveCountMax 3

scp命令经常用在主机之间拷贝文件用,但是如果目标机器的sshd的端口不是默认的22,怎么办呢?

scp -P 1111 [email protected]:/home/xxx

这样就可以配合ssh-keygen -t rsa命令将生成的pub重命名为authorized_keys,并拷贝至目标机器的~/.ssh/文件夹下,这样以后就可以无密码登录ssh了。