分类 默认分类 下的文章

自文章:https://learnku.com/articles/64097

手动DNS申请SSL证书

# 手动DNS申请
acme.sh --issue -d www.xxx.com,m.xxx.com --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please
#会报错,提示需要解析
#手动解析后再尝试执行命令,加上 --renew  参数
acme.sh --renew -d www.xxx.com,m.xxx.com --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please
#如果同时申请多个域名,--renew出现以下报错的话,可能需要改成单个域名才能找到申请的目录
#报错:
'm.xx.com,www.xx.com' is not an issued domain, skipping.
#换成单个域名(第一个域名,因为申请的时候key放到这个目录了m.xx.com_ecc/m.xx.com.key,renew的时候去m.xx.com,www.xx.com这个目录找,找不到文件)
acme.sh --renew -d m.xx.com --dns --yes-I-know-dns-manual-mode-enough-go-ahead-please
  1. 安装 acme.sh#
    以下三种任选一种即可,把 my@example.com 修改成自己的邮箱。

安装过程不会污染任何功能和文件,所有的修改都限制在安装目录中:~/.acme.sh/。

(1)通过 https://get.acme.sh 安装
curl https://get.acme.sh | sh -s email=my@example.com
或者

wget -O - https://get.acme.sh | sh -s email=my@example.com
(1)通过 GitHub 安装
curl https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh | sh -s -- --install-online -m my@example.com
或者

wget -O - https://raw.githubusercontent.com/acmesh-official/acme.sh/master/acme.sh | sh -s -- --install-online -m my@example.com
(3)通过 git clone 安装

使用加速通道

git clone https://github.com.cnpmjs.org/acmesh-official/acme.sh.git
cd acme.sh
./acme.sh --install -m my@example.com
安装过程进行了以下几步:
(1)acme.sh 安装到 home 目录下

~/.acme.sh/
(2)创建一个 bash 的 alias

alias acme.sh=~/.acme.sh/acme.sh
(3)创建 cronjob,每天 0:00 自动检测所有证书,如果快过期了,会自动更新证书。

  1. 生成证书
    以下两种任选一种即可,把 mydomain.com 更换成自己的域名。

如何生成泛域名证书,请参阅 使用 acme.sh 生成免费的泛域名证书

(1)http 方式
指定域名,并指定网站根目录。 acme.sh 会全自动生成验证文件,并放到网站的根目录,自动完成验证。最后会删除验证文件,整个过程没有任何副作用。

acme.sh --issue -d mydomain.com -d www.mydomain.com --webroot /home/wwwroot/mydomain.com/
如果使用 apache 服务器, acme.sh 可以智能的从 apache 的配置中自动完成验证,不需要指定网站根目录:

acme.sh --issue -d mydomain.com --apache
如果使用 nginx 服务器,或者反向代理,acme.sh 可以智能的从 nginx 的配置中自动完成验证,不需要指定网站根目录:

acme.sh --issue -d mydomain.com --nginx
注意!无论是 apache 还是 nginx 模式,acme.sh 不会自动修改配置文件,需要手动修改配置文件,否则无法访问 https

如果还没有运行任何 web 服务,80 端口是空闲的,那么 acme.sh 还能假装自己是一个 webserver,临时监听 80 端口,完成验证:

acme.sh --issue -d mydomain.com --standalone
(2)DNS 方式
好处:不需要任何服务器,不需要任何公网 IP, 只需要 DNS 的解析记录即可完成验证。

坏处:如果不同时配置 Automatic DNS API 则 acme.sh 将无法自动更新证书。

acme.sh --issue --dns -d mydomain.com \
--yes-I-know-dns-manual-mode-enough-go-ahead-please
acme.sh 会生成相应的解析记录,到域名解析中添加 TXT 记录,解析成功后,重新生成证书。

acme.sh --renew -d mydomain.com \
--yes-I-know-dns-manual-mode-enough-go-ahead-please
DNS 方式的真正强大之处在于可以使用域名解析商提供的 api 自动添加 TXT 记录完成验证。

acme.sh 目前支持几十种域名服务商:dnsapi

以 dnspod 为例,需要先登录到 dnspod 账号,生成 api id 和 api key

export DP_Id="1234"

export DP_Key="qwertyuiopasdfghjkl"

acme.sh --issue --dns dns_dp -d mydomain.com -d www.mydomain.com
acme.sh 会自动生成证书,并且会记录 api id 和 api key 以后再使用 dnspod api 时就不需要再指定了。

  1. 复制 / 安装 证书
    注意!默认生成的证书都放在安装目录下:~/.acme.sh/,不要直接使用此目录下的文件,这里面的文件都是内部使用,而且目录结构可能会变化。

正确的使用方法是使用 --install-cert 命令,指定目标位置,证书文件会被复制到相应的位置。

Apache
acme.sh --install-cert -d example.com \
--cert-file /path/to/certfile/in/apache/cert.pem \
--key-file /path/to/keyfile/in/apache/key.pem \
--fullchain-file /path/to/fullchain/certfile/apache/fullchain.pem \
--reloadcmd "service apache2 force-reload"
Nginx
acme.sh --install-cert -d example.com \
--key-file /path/to/keyfile/in/nginx/key.pem \
--fullchain-file /path/to/fullchain/nginx/cert.pem \
--reloadcmd "service nginx force-reload"

  1. 更新证书
    证书在 60 天以后会自动更新,无需任何操作。
  2. 更新 acme.sh
    升级 acme.sh 到最新版

acme.sh --upgrade
如果不想手动升级,也可以开启自动升级

acme.sh --upgrade --auto-upgrade
关闭自动更新

acme.sh --upgrade --auto-upgrade 0

  1. 出错怎么办
    在命令后添加 --debug 或 --debug 2 比如:

acme.sh --issue -d mydomain.com --nginx --debug

acme.sh --issue -d mydomain.com --nginx --debug 2
或者查阅日志

~/.acme.sh/acme.sh.log

GITHUB地址

<?php

// 字符串转BcMath计算结果
class StrToBcmath {
    /**
     * @var int
     */
    private $scale; // 精度

    /**
     * @var mixed   // 是否输出计算过程
     */
    private $isecho;

    /**
     * @param $scale    // 可选,精度,默认值:8
     * @param $isecho   // 可选,是否输出计算过程,默认值:false
     */
    public function __construct($scale = 8, $isecho = false) {
        $this->scale  = $scale;
        $this->isecho = $isecho;
    }

    // 主方法
    /**
     * @param $expression   // 复杂运算表达式
     * @param $scale    // 精度
     * @param $isRecursive  // 是否递归,递归时不输出计算过程
     */
    public function of($expression, $scale = '', $isRecursive = false) {
        $scale = $scale ?: $this->scale;

        // 原始表达式
        if (!$isRecursive && $this->isecho) {
            echo $expression . "\n";
        }

        // 去除空格
        if (!$isRecursive) {
            $expression = str_replace(' ', '', $expression);
        }

        //避免$expression=0,出现InvalidArgumentException错误
        if (is_numeric($expression) && $expression == 0) return 0;

        // 如果输入的表达式为空或者包含非法字符,则抛出异常
        if (empty($expression) || preg_match('/[^0-9\.\+\-\*\/\(\)]/', $expression)) {
            throw new \InvalidArgumentException('表达式错误,仅支持+,-,*,/,**,(),数字:' . $expression);
        }

        // 使用正则表达式匹配表达式中的括号
        while (preg_match('/\(([^\(\)]+)\)/', $expression, $matches)) {
            // 计算括号中的表达式
            $res = $this->of($matches[1], $scale, true);
            // 将没有括号的表达式替换到原表达式中
            $expression = str_replace('(' . $matches[1] . ')', $res, $expression);
            if ($this->isecho) {
                echo '=' . $expression . "\n";
            }
        }

        // 处理指数运算
        while (preg_match('/(\d+(\.\d+)?)(\*\*)(\d+(\.\d+)?)/', $expression, $matches)) {
            $res        = $this->basic($matches[0], $scale);
            $expression = str_replace($matches[0], $res, $expression);
            if (!$isRecursive && $this->isecho) {
                echo '=' . $expression . "\n";
            }
        }

        // 处理乘法、除法
        while (preg_match('/(\d+(\.\d+)?)([\/*])(\d+(\.\d+)?)/', $expression, $matches)) {
            $res        = $this->basic($matches[0], $scale);
            $expression = str_replace($matches[0], $res, $expression);
            if (!$isRecursive && $this->isecho) {
                echo '=' . $expression . "\n";
            }
        }
        // 处理加法和减法
        while (preg_match('/(-?\d+(\.\d+)?)([+\-])(-?\d+(\.\d+)?)/', $expression, $matches)) {
            $res        = $this->basic($matches[0], $scale);
            $expression = str_replace($matches[0], $res, $expression);
            if (!$isRecursive && $this->isecho) {
                echo '=' . $expression . "\n";
            }
        }
        // 返回计算结果
        return $expression;
    }

    // 基本的四则运算
    /**
     * @param $expression   // 基本的四则运算表达式
     * @param $scale    // 精度
     */
    public function basic($expression, $scale = '') {
        $scale = $scale ?: $this->scale;
        // 使用正则表达式匹配表达式中的两个操作数和一个运算符
        if (!preg_match('/^(-?\d+(\.\d+)?)([\/*+-]|(\*\*))(-?\d+(\.\d+)?)$/', $expression, $matches)) {
            throw new \InvalidArgumentException('表达式错误,不符合基本的四则运算:' . $expression);
        }
        // dump($matches);
        // 根据运算符调用对应的 bcmath 函数
        $operator = $matches[3];
        $a        = strval($matches[1]);
        $b        = strval($matches[5]);
        // if ($this->isecho) {
        //     echo '【处理运算符】' . $a . $operator . $b . "\n";
        // }
        try {
            switch ($operator) {
            case '+':
                return bcadd($a, $b, $scale);
            case '-':
                return bcsub($a, $b, $scale);
            case '*':
                return bcmul($a, $b, $scale);
            case '/':
                if ($b == 0) {
                    throw new \InvalidArgumentException('除数不能为零:' . $a . $operator . $b);
                }
                return bcdiv($a, $b, $scale);
            case '**':
                if (strpos($b, '.') !== false) {
                    if ((int) $b == $b) {
                        $b = (int) $b;
                    } else {
                        throw new \InvalidArgumentException('指数不能为小数:' . $a . $operator . $b);
                    }
                }
                return bcpow($a, $b, $scale);
            default:
                throw new \InvalidArgumentException('未知的运算符:' . $a . $operator . $b);
            }
        } catch (\Exception $e) {
            throw new \InvalidArgumentException($e->getMessage());
        }
    }

}

class CComponent
{
    private $_e;
    private $_m;

    /**
     * Returns a property value, an event handler list or a behavior based on its name.
     * Do not call this method. This is a PHP magic method that we override
     * to allow using the following syntax to read a property or obtain event handlers:
     * <pre>
     * $value=$component->propertyName;
     * $handlers=$component->eventName;
     * </pre>
     * @param string $name the property name or event name
     * @return mixed the property value, event handlers attached to the event, or the named behavior
     * @throws CException if the property or event is not defined
     * @see __set
     */
    public function __get($name)
    {
        $getter='get'.$name;
        if(method_exists($this,$getter))
            return $this->$getter();
        elseif(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
        {
            // duplicating getEventHandlers() here for performance
            $name=strtolower($name);
            if(!isset($this->_e[$name]))
                $this->_e[$name]=new CList;
            return $this->_e[$name];
        }
        elseif(isset($this->_m[$name]))
            return $this->_m[$name];
        elseif(is_array($this->_m))
        {
            foreach($this->_m as $object)
            {
                if($object->getEnabled() && (property_exists($object,$name) || $object->canGetProperty($name)))
                    return $object->$name;
            }
        }
        throw new CException(Yii::t('yii','Property "{class}.{property}" is not defined.',
            array('{class}'=>get_class($this), '{property}'=>$name)));
    }

    /**
     * Sets value of a component property.
     * Do not call this method. This is a PHP magic method that we override
     * to allow using the following syntax to set a property or attach an event handler
     * <pre>
     * $this->propertyName=$value;
     * $this->eventName=$callback;
     * </pre>
     * @param string $name the property name or the event name
     * @param mixed $value the property value or callback
     * @return mixed
     * @throws CException if the property/event is not defined or the property is read only.
     * @see __get
     */
    public function __set($name,$value)
    {
        $setter='set'.$name;
        if(method_exists($this,$setter))
            return $this->$setter($value);
        elseif(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
        {
            // duplicating getEventHandlers() here for performance
            $name=strtolower($name);
            if(!isset($this->_e[$name]))
                $this->_e[$name]=new CList;
            return $this->_e[$name]->add($value);
        }
        elseif(is_array($this->_m))
        {
            foreach($this->_m as $object)
            {
                if($object->getEnabled() && (property_exists($object,$name) || $object->canSetProperty($name)))
                    return $object->$name=$value;
            }
        }
        if(method_exists($this,'get'.$name))
            throw new CException(Yii::t('yii','Property "{class}.{property}" is read only.',
                array('{class}'=>get_class($this), '{property}'=>$name)));
        else
            throw new CException(Yii::t('yii','Property "{class}.{property}" is not defined.',
                array('{class}'=>get_class($this), '{property}'=>$name)));
    }

    /**
     * Checks if a property value is null.
     * Do not call this method. This is a PHP magic method that we override
     * to allow using isset() to detect if a component property is set or not.
     * @param string $name the property name or the event name
     * @return boolean
     */
    public function __isset($name)
    {
        $getter='get'.$name;
        if(method_exists($this,$getter))
            return $this->$getter()!==null;
        elseif(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
        {
            $name=strtolower($name);
            return isset($this->_e[$name]) && $this->_e[$name]->getCount();
        }
        elseif(is_array($this->_m))
        {
             if(isset($this->_m[$name]))
                 return true;
            foreach($this->_m as $object)
            {
                if($object->getEnabled() && (property_exists($object,$name) || $object->canGetProperty($name)))
                    return $object->$name!==null;
            }
        }
        return false;
    }

    /**
     * Sets a component property to be null.
     * Do not call this method. This is a PHP magic method that we override
     * to allow using unset() to set a component property to be null.
     * @param string $name the property name or the event name
     * @throws CException if the property is read only.
     * @return mixed
     */
    public function __unset($name)
    {
        $setter='set'.$name;
        if(method_exists($this,$setter))
            $this->$setter(null);
        elseif(strncasecmp($name,'on',2)===0 && method_exists($this,$name))
            unset($this->_e[strtolower($name)]);
        elseif(is_array($this->_m))
        {
            if(isset($this->_m[$name]))
                $this->detachBehavior($name);
            else
            {
                foreach($this->_m as $object)
                {
                    if($object->getEnabled())
                    {
                        if(property_exists($object,$name))
                            return $object->$name=null;
                        elseif($object->canSetProperty($name))
                            return $object->$setter(null);
                    }
                }
            }
        }
        elseif(method_exists($this,'get'.$name))
            throw new CException(Yii::t('yii','Property "{class}.{property}" is read only.',
                array('{class}'=>get_class($this), '{property}'=>$name)));
    }

    /**
     * Calls the named method which is not a class method.
     * Do not call this method. This is a PHP magic method that we override
     * to implement the behavior feature.
     * @param string $name the method name
     * @param array $parameters method parameters
     * @throws CException if current class and its behaviors do not have a method or closure with the given name
     * @return mixed the method return value
     */
    public function __call($name,$parameters)
    {
        if($this->_m!==null)
        {
            foreach($this->_m as $object)
            {
                if($object->getEnabled() && method_exists($object,$name))
                    return call_user_func_array(array($object,$name),$parameters);
            }
        }
        if(class_exists('Closure', false) && ($this->canGetProperty($name) || property_exists($this, $name)) && $this->$name instanceof Closure)
            return call_user_func_array($this->$name, $parameters);
        throw new CException(Yii::t('yii','{class} and its behaviors do not have a method or closure named "{name}".',
            array('{class}'=>get_class($this), '{name}'=>$name)));
    }

    /**
     * Returns the named behavior object.
     * The name 'asa' stands for 'as a'.
     * @param string $behavior the behavior name
     * @return IBehavior the behavior object, or null if the behavior does not exist
     */
    public function asa($behavior)
    {
        return isset($this->_m[$behavior]) ? $this->_m[$behavior] : null;
    }

    /**
     * Attaches a list of behaviors to the component.
     * Each behavior is indexed by its name and should be an instance of
     * {@link IBehavior}, a string specifying the behavior class, or an
     * array of the following structure:
     * <pre>
     * array(
     *     'class'=>'path.to.BehaviorClass',
     *     'property1'=>'value1',
     *     'property2'=>'value2',
     * )
     * </pre>
     * @param array $behaviors list of behaviors to be attached to the component
     */
    public function attachBehaviors($behaviors)
    {
        foreach($behaviors as $name=>$behavior)
            $this->attachBehavior($name,$behavior);
    }

    /**
     * Detaches all behaviors from the component.
     */
    public function detachBehaviors()
    {
        if($this->_m!==null)
        {
            foreach($this->_m as $name=>$behavior)
                $this->detachBehavior($name);
            $this->_m=null;
        }
    }

    /**
     * Attaches a behavior to this component.
     * This method will create the behavior object based on the given
     * configuration. After that, the behavior object will be initialized
     * by calling its {@link IBehavior::attach} method.
     * @param string $name the behavior's name. It should uniquely identify this behavior.
     * @param mixed $behavior the behavior configuration. This is passed as the first
     * parameter to {@link YiiBase::createComponent} to create the behavior object.
     * You can also pass an already created behavior instance (the new behavior will replace an already created
     * behavior with the same name, if it exists).
     * @return IBehavior the behavior object
     */
    public function attachBehavior($name,$behavior)
    {
        if(!($behavior instanceof IBehavior))
            $behavior=Yii::createComponent($behavior);
        $behavior->setEnabled(true);
        $behavior->attach($this);
        return $this->_m[$name]=$behavior;
    }

    /**
     * Detaches a behavior from the component.
     * The behavior's {@link IBehavior::detach} method will be invoked.
     * @param string $name the behavior's name. It uniquely identifies the behavior.
     * @return IBehavior the detached behavior. Null if the behavior does not exist.
     */
    public function detachBehavior($name)
    {
        if(isset($this->_m[$name]))
        {
            $this->_m[$name]->detach($this);
            $behavior=$this->_m[$name];
            unset($this->_m[$name]);
            return $behavior;
        }
    }

    /**
     * Enables all behaviors attached to this component.
     */
    public function enableBehaviors()
    {
        if($this->_m!==null)
        {
            foreach($this->_m as $behavior)
                $behavior->setEnabled(true);
        }
    }

    /**
     * Disables all behaviors attached to this component.
     */
    public function disableBehaviors()
    {
        if($this->_m!==null)
        {
            foreach($this->_m as $behavior)
                $behavior->setEnabled(false);
        }
    }

    /**
     * Enables an attached behavior.
     * A behavior is only effective when it is enabled.
     * A behavior is enabled when first attached.
     * @param string $name the behavior's name. It uniquely identifies the behavior.
     */
    public function enableBehavior($name)
    {
        if(isset($this->_m[$name]))
            $this->_m[$name]->setEnabled(true);
    }

    /**
     * Disables an attached behavior.
     * A behavior is only effective when it is enabled.
     * @param string $name the behavior's name. It uniquely identifies the behavior.
     */
    public function disableBehavior($name)
    {
        if(isset($this->_m[$name]))
            $this->_m[$name]->setEnabled(false);
    }

    /**
     * Determines whether a property is defined.
     * A property is defined if there is a getter or setter method
     * defined in the class. Note, property names are case-insensitive.
     * @param string $name the property name
     * @return boolean whether the property is defined
     * @see canGetProperty
     * @see canSetProperty
     */
    public function hasProperty($name)
    {
        return method_exists($this,'get'.$name) || method_exists($this,'set'.$name);
    }

    /**
     * Determines whether a property can be read.
     * A property can be read if the class has a getter method
     * for the property name. Note, property name is case-insensitive.
     * @param string $name the property name
     * @return boolean whether the property can be read
     * @see canSetProperty
     */
    public function canGetProperty($name)
    {
        return method_exists($this,'get'.$name);
    }

    /**
     * Determines whether a property can be set.
     * A property can be written if the class has a setter method
     * for the property name. Note, property name is case-insensitive.
     * @param string $name the property name
     * @return boolean whether the property can be written
     * @see canGetProperty
     */
    public function canSetProperty($name)
    {
        return method_exists($this,'set'.$name);
    }

    /**
     * Determines whether an event is defined.
     * An event is defined if the class has a method named like 'onXXX'.
     * Note, event name is case-insensitive.
     * @param string $name the event name
     * @return boolean whether an event is defined
     */
    public function hasEvent($name)
    {
        return !strncasecmp($name,'on',2) && method_exists($this,$name);
    }

    /**
     * Checks whether the named event has attached handlers.
     * @param string $name the event name
     * @return boolean whether an event has been attached one or several handlers
     */
    public function hasEventHandler($name)
    {
        $name=strtolower($name);
        return isset($this->_e[$name]) && $this->_e[$name]->getCount()>0;
    }

    /**
     * Returns the list of attached event handlers for an event.
     * @param string $name the event name
     * @return CList list of attached event handlers for the event
     * @throws CException if the event is not defined
     */
    public function getEventHandlers($name)
    {
        if($this->hasEvent($name))
        {
            $name=strtolower($name);
            if(!isset($this->_e[$name]))
                $this->_e[$name]=new CList;
            return $this->_e[$name];
        }
        else
            throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.',
                array('{class}'=>get_class($this), '{event}'=>$name)));
    }

    /**
     * Attaches an event handler to an event.
     *
     * An event handler must be a valid PHP callback, i.e., a string referring to
     * a global function name, or an array containing two elements with
     * the first element being an object and the second element a method name
     * of the object.
     *
     * An event handler must be defined with the following signature,
     * <pre>
     * function handlerName($event) {}
     * </pre>
     * where $event includes parameters associated with the event.
     *
     * This is a convenient method of attaching a handler to an event.
     * It is equivalent to the following code:
     * <pre>
     * $component->getEventHandlers($eventName)->add($eventHandler);
     * </pre>
     *
     * Using {@link getEventHandlers}, one can also specify the execution order
     * of multiple handlers attaching to the same event. For example:
     * <pre>
     * $component->getEventHandlers($eventName)->insertAt(0,$eventHandler);
     * </pre>
     * makes the handler to be invoked first.
     *
     * @param string $name the event name
     * @param callback $handler the event handler
     * @throws CException if the event is not defined
     * @see detachEventHandler
     */
    public function attachEventHandler($name,$handler)
    {
        $this->getEventHandlers($name)->add($handler);
    }

    /**
     * Detaches an existing event handler.
     * This method is the opposite of {@link attachEventHandler}.
     * @param string $name event name
     * @param callback $handler the event handler to be removed
     * @return boolean if the detachment process is successful
     * @see attachEventHandler
     */
    public function detachEventHandler($name,$handler)
    {
        if($this->hasEventHandler($name))
            return $this->getEventHandlers($name)->remove($handler)!==false;
        else
            return false;
    }

    /**
     * Raises an event.
     * This method represents the happening of an event. It invokes
     * all attached handlers for the event.
     * @param string $name the event name
     * @param CEvent $event the event parameter
     * @throws CException if the event is undefined or an event handler is invalid.
     */
    public function raiseEvent($name,$event)
    {
        $name=strtolower($name);
        if(isset($this->_e[$name]))
        {
            foreach($this->_e[$name] as $handler)
            {
                if(is_string($handler))
                    call_user_func($handler,$event);
                elseif(is_callable($handler,true))
                {
                    if(is_array($handler))
                    {
                        // an array: 0 - object, 1 - method name
                        list($object,$method)=$handler;
                        if(is_string($object))    // static method call
                            call_user_func($handler,$event);
                        elseif(method_exists($object,$method))
                            $object->$method($event);
                        else
                            throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".',
                                array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>$handler[1])));
                    }
                    else // PHP 5.3: anonymous function
                        call_user_func($handler,$event);
                }
                else
                    throw new CException(Yii::t('yii','Event "{class}.{event}" is attached with an invalid handler "{handler}".',
                        array('{class}'=>get_class($this), '{event}'=>$name, '{handler}'=>gettype($handler))));
                // stop further handling if param.handled is set true
                if(($event instanceof CEvent) && $event->handled)
                    return;
            }
        }
        elseif(YII_DEBUG && !$this->hasEvent($name))
            throw new CException(Yii::t('yii','Event "{class}.{event}" is not defined.',
                array('{class}'=>get_class($this), '{event}'=>$name)));
    }

    /**
     * Evaluates a PHP expression or callback under the context of this component.
     *
     * Valid PHP callback can be class method name in the form of
     * array(ClassName/Object, MethodName), or anonymous function (only available in PHP 5.3.0 or above).
     *
     * If a PHP callback is used, the corresponding function/method signature should be
     * <pre>
     * function foo($param1, $param2, ..., $component) { ... }
     * </pre>
     * where the array elements in the second parameter to this method will be passed
     * to the callback as $param1, $param2, ...; and the last parameter will be the component itself.
     *
     * If a PHP expression is used, the second parameter will be "extracted" into PHP variables
     * that can be directly accessed in the expression. See {@link http://us.php.net/manual/en/function.extract.php PHP extract}
     * for more details. In the expression, the component object can be accessed using $this.
     *
     * A PHP expression can be any PHP code that has a value. To learn more about what an expression is,
     * please refer to the {@link http://www.php.net/manual/en/language.expressions.php php manual}.
     *
     * @param mixed $_expression_ a PHP expression or PHP callback to be evaluated.
     * @param array $_data_ additional parameters to be passed to the above expression/callback.
     * @return mixed the expression result
     * @since 1.1.0
     */
    public function evaluateExpression($_expression_,$_data_=array())
    {
        if(is_string($_expression_))
        {
            extract($_data_);
            try
            {
                return eval('return ' . $_expression_ . ';');
            }
            catch (ParseError $e)
            {
                return false;
            }
        }
        else
        {
            $_data_[]=$this;
            return call_user_func_array($_expression_, array_values($_data_));
        }
    }
}

在PHP应用中,超时时间的设置对于应用的性能和稳定性至关重要。超时时间配置不当可能导致应用响应缓慢、资源占用过高,甚至引发服务崩溃。本文将详细解析PHP配置文件php.ini和php-fpm.conf中的超时时间设置,帮助读者深入理解这些设置的作用、影响以及如何合理配置。

一、php.ini中的超时时间设置

max_execution_time
max_execution_time 是php.ini中的一个重要设置,它定义了PHP脚本的最大执行时间。当脚本运行时间超过这个值时,PHP会终止脚本的执行并返回一个致命错误。这个设置对于防止恶意脚本或无限循环脚本占用过多资源非常有用。

默认情况下,max_execution_time 的值为30秒。在实际应用中,我们可以根据应用的需求和性能要求来合理设置这个值。需要注意的是,这个设置只影响PHP脚本本身的执行时间,不包括脚本执行过程中可能发生的数据库查询、文件操作等外部操作的时间。

set_time_limit() 可以在php代码中更改执行时间 max_execution_time 的定义。

implicit_flush
implicit_flush 是一个影响输出缓冲设置的选项。当implicit_flush设置为On时,PHP会在每次输出内容时自动刷新输出缓冲区,这样可以确保用户能够实时看到输出的内容。然而,频繁的刷新输出缓冲区可能会降低应用的性能。因此,在需要实时输出内容的情况下,我们可以将implicit_flush设置为On;在其他情况下,建议将其设置为Off以提高性能。

二、php-fpm.conf中的超时时间设置

request_terminate_timeout
[www] 范围
request_terminate_timeout 是php-fpm.conf中的一个设置,它定义了PHP-FPM进程在处理请求时的最大执行时间。当请求的处理时间超过这个值时,PHP-FPM会强制终止该请求并返回一个错误。这个设置有助于防止长时间运行的请求占用过多的资源。

默认情况下,request_terminate_timeout 的值为0,表示禁用超时限制。在实际应用中,我们可以根据应用的需求和性能要求来合理设置这个值。需要注意的是,这个设置的值应该大于max_execution_time的值,以确保PHP脚本有足够的时间来执行。

process_control_timeout
php-fpm 全局
process_control_timeout 是php-fpm.conf中的另一个重要设置,它定义了PHP-FPM进程控制操作的超时时间。当PHP-FPM需要启动、重启或关闭子进程时,如果超过了这个时间限制,PHP-FPM会放弃该操作并返回一个错误。这个设置有助于防止PHP-FPM进程控制操作因为各种原因(如资源不足、网络延迟等)而无限期地等待。

默认情况下,process_control_timeout 的值为0,表示禁用超时限制。然而,在实际应用中,我们建议设置一个合理的值来确保PHP-FPM进程控制操作的稳定性和可靠性。

三、总结

通过本文的解析,我们深入了解了PHP配置文件php.ini和php-fpm.conf中的超时时间设置。这些设置对于提高PHP应用的性能和稳定性具有重要意义。在实际应用中,我们应该根据应用的需求和性能要求来合理配置这些值,以确保应用的正常运行和高效性能。同时,我们还需要关注这些设置可能带来的潜在风险和问题,并采取相应的措施来避免和解决这些问题。

希望本文能够帮助读者更好地理解PHP配置文件中的超时时间设置,并为实际应用中的配置提供参考和指导。