首页 > 编程技术 > php

工作中的几个Drupal小问题记录总结

发布时间:2016-11-25 17:21

以下是最近工作中总结的几个Drupal小问题,Drupal性能模块之简明分析对比,实现view动态输出的步骤方法,为Drupal主题添加主题内自带图片的正确方法。其中第一个是在网上找到的翻译国外内容,这此感谢这些默默翻译的高手。

Drupal性能模块的简明分析对比

原文:

Varnish

We explored various caching solutions available for Drupal. We shortlisted Varnish, Boost and Authcache modules. We performed a number of tests using these modules. We tested over 1000 pages from different locations. The average page load time without any caching was above 4.0 seconds. The average page load time with Drupal's default caching was 2.5 seconds. The average page load time with the Authcache module was reduced to 1.8 seconds. The average page load time with the Boost module was 1.7 seconds. The average page load time with Varnish module was 1.5 seconds. Therefore we preferred using the Varnish module. These stats are for this site only, the results may vary for other sites.

我简单翻译下:

用1000个不同的页面作的测试,

1.不用任何缓存模块:平均加载时间4秒以上;
2.使用drupal自带缓存:平均加载时间2.5秒;
3.使用Authcache模块,平均加载时间1.8秒;
4.使用Boost模块,平均加载时间1.7秒;
5.使用Varnish模块,平均加载时间1.5秒;

-----------------------------------------------

实现view动态输出的步骤方法

1、在 view 的属性页,选择 header
2、选择 Global: Text area
3、在弹出框里,覆写 输出
4、只有Replacement patterns 显示出来的字段,才能被调用
5、注意勾选 *Use replacement tokens from the first row

-----------------------------------------------

为Drupal主题添加主题内自带图片的正确方法

在为drupal的主题添加主题自带的一些图片的时候,会碰到一些路径问题,使用下面这些方法添加的图片,才能正确显示在页面上:

<img" width=100% src="<?php print $base_path . drupal_get_path('theme', 'yourtheme');?>/image/act-title.jpg">

在php标签里面输出url的时候要使用 $base_path 与 主题路径拼接出来的url 然后再加上主题目录里面的静态图片的路径,才能正确的显示.

现在这种多选择功能在很多网站都有,如现在很多电商网站都有N个条件选择了,下面小编为各位介绍一个简单的多级分类筛选实现方法。

主要注意这边有一个 $$这是变量的变量。 以后估计会常用这个做开发。

 代码如下 复制代码

<?php
 
$conditions = array('price','color','metal');//要进行筛选的字段放在这里
 
$price = $color = $metal='';//先给需要筛选的字段赋空值,这些值将输出到页面的hidden fileds 中
 
//以下循环给已经进行的筛选赋值,以便能够在下一次筛选中保留
 
foreach($conditions as $value){
 
    if(isset($_GET[$value])){
        $$value = $_GET[$value];
    }
 
}

 
//以下是演示输出$_GET数据
 
echo '<pre>';
 
print_r($_GET);
 
echo '</pre>';
 
?>
 
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
 
<html xmlns="http://www.w3.org/1999/xhtml">
 
<head>
 
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 
<title>分类筛选演示</title>
 
<style type="text/css">
 
body{font-size:14px;font-family:Tahoma,"宋体"}
 
</style>
 
<script type="text/javascript">
 
function Filter(a,b){
 
    var $ = function(e){return document.getElementById(e);}
 
    var ipts = $('filterForm').getElementsByTagName('input'),result=[];
 
    for(var i=0,l=ipts.length;i<l;i++){
 
        if(ipts[i].getAttribute('to')=='filter'){
 
           result.push(ipts[i]);
 
       }
 
    }
 
   if($(a)){
 
        $(a).value = b;
 
        for(var j=0,len=result.length;j<len;j++){
 
           if(result[j].value==''){
 
               result[j].parentNode.removeChild(result[j]);
 
           }
 
       }
 
        document.forms['filterForm'].submit();
 
    }
 
    return false;
 
}
 
</script>
 
</head>
 
<body>
 
<form id="filterForm" action="test.php" method="get">
 
<!--
 
form的id 要和程序里统一
 
为避免与其他使用的隐藏域冲突,添加了to属性
 
以下是筛选字段隐藏域
 
需要筛选的隐藏域需要加 to 属性
 
-->
 
<input to="filter" type="hidden" id="price" name="price" value="<?=$price?>" />
 
<input to="filter" type="hidden" id="color" name="color" value="<?=$color?>" />
 
<input to="filter" type="hidden" id="metal" name="metal" value="<?=$metal?>" />
 
</form>
 
<!--
 
要筛选的属性可以由程序生成,注意规律!
 
-->
 
价格:<a href="javascript:Filter('price','');">不限</a>

<a href="javascript:Filter('price','100-1000');">100-1000</a>
 
      <a href="javascript:Filter('price','1001-2000');">1001-2000</a>
 
     <a href="javascript:Filter('price','2001-3000');">2001-3000</a><br/>
 
颜色:<a href="javascript:Filter('color','红色');">红色</a>
 
      <a href="javascript:Filter('color','蓝色');">蓝色</a><br />
 
材质:<a href="javascript:Filter('metal','纯金');">纯金</a>
 
      <a href="javascript:Filter('metal','纯银');">纯银</a><br />
 
</body>
 
</html>

验证URL有两种一种是利用正则表达式来验证URL是不是合适url规则了,另一个是利用函数来访问指定url看看是否可正常访问了,如果能正常访问自然就是合法的url地址了。

例子1

 代码如下 复制代码

<?php
function isValidUrl($url) {
 
    $patern = '/^http[s]?:\/\/'.
        '(([0-9]{1,3}\.){3}[0-9]{1,3}'.             // IP形式的URL- 199.194.52.184
        '|'.                                        // 允许IP和DOMAIN(域名)
        '([0-9a-z_!~*\'()-]+\.)*'.                  // 三级域验证- www.
        '([0-9a-z][0-9a-z-]{0,61})?[0-9a-z]\.'.     // 二级域验证
        '[a-z]{2,6})'.                              // 顶级域验证.com or .museum
        '(:[0-9]{1,4})?'.                           // 端口- :80
        '((\/\?)|'.                                 // 如果含有文件对文件部分进行校验
        '(\/[0-9a-zA-Z_!~\*\'\(\)\.;\?:@&=\+\$,%#-\/]*)?)$/';
 
    if(!preg_match($patern, $url)) {
        die( '您输入的URL格式有问题,请检查!');
    }
}

例子2

上面的例子只是验证url是不是正常的不代表是否可以访问了,我们可以使用如curl函数进行方法

 代码如下 复制代码

$url = "http://www.111cn.net ";
$curl = curl_init($url);
curl_setopt($curl, CURLOPT_NOBODY, true);
$result = curl_exec($curl);
if ($result !== false)
{
  $statusCode = curl_getinfo($curl, CURLINFO_HTTP_CODE); 
  if ($statusCode == 404)
  {
    echo "URL Not Exists"
  }
  else
  {
     echo "URL Exists";
  }
}
else
{
  echo "URL not Exists";
}

除了这个函数还可以使用php的很多函数如 file、file_get_contents()、fopen函数来进行检测了。

Gravatar头像是现在博客通用的一个调用方法了,很多朋友的个人博客都使用了Gravatar头像了,但最近有很多站长发现Gravatar头像打开缓慢了,那么我们要如何解决Gravatar图片打不开或者打开慢的问题呢?下面来看看吧。

第一、如果我们还需要使用Gravatar头像

 代码如下 复制代码
function get_ssl_avatar($avatar) {
$avatar = preg_replace('/.*\/avatar\/(.*)\?s=([\d]+)&.*/','<img" width=100% src="https://secure.gravatar.com/avatar/$1?s=$2" class="avatar avatar-$2" height="$2" width="$2">',$avatar);
return $avatar;
}
add_filter('get_avatar', 'get_ssl_avatar');

在当前WORDPRESS主题中的FUNCTIONS.PHP页面中加入上面的代码,因为HTTP直接访问不了,这里调整为HTTPS的路径地址。
第二、使用本地头像

 代码如下 复制代码
function my_avatar($avatar) {
$tmp = strpos($avatar, 'http');
$g = substr($avatar, $tmp, strpos($avatar, "'", $tmp) - $tmp);
$tmp = strpos($g, 'avatar/') + 7;
$f = substr($g, $tmp, strpos($g, "?", $tmp) - $tmp);
$w = get_bloginfo('wpurl');
$e = ABSPATH .'avatar/'. $f .'.jpg';
$t = 1209600;
if ( !is_file($e) || (time() - filemtime($e)) > $t ) {
copy(htmlspecialchars_decode($g), $e);
} else $avatar = strtr($avatar, array($g => $w.'/avatar/'.$f.'.jpg'));
if (filesize($e) < 500) copy($w.'/avatar/default.jpg', $e);
return $avatar;
}
add_filter('get_avatar', 'my_avatar');

同样的,在FUNCTIONS.PHP文件中,加入上面的代码,把头像缓存本地,同样的使用avatar文件夹作为根目录,可以先放入一个default.jpg作为默认不存在的头像展示图片。
第三、使用第三方评论插件
使用第三方评论插件可以展示头像的,目前不存在调用问题,之前老左也写过一篇"点评四款社会化评论系统",目前使用较多的还是多说和畅言,前者用户体验还可以,就是服务器宕机不稳定。后者基于搜狐提供的,界面一般,但服务器是比较稳定的。

以前我们讲过php单态设计模式之单例模式的理解及单例模式(Singleton)的常见应用场景,现在我们在原来的基础上总结一下。

相关文章:析php单态设计模式之单例模式的理解

相关文章:php设计模式——单例模式(Singleton)的常见应用场景<

 

单例模式,就是保持一个对象只存在一个实例。并且为该唯一实例提供一个全局访问点(一般是一个静态的getInstance方法)。单例模式应用场景非常广泛,例如:

数据库操作对象
日志写入对象
全局配置解析对象等

这些场景的共同特征是从业务逻辑上来看运行期间改对象却是只需要一个实例、不断new多个实例会增加不必要的资源消耗、全局调用便利。下面分别说明这三个方面:

1. 业务上只需要一个实例


以数据库连接对象为例,加入有一个购物网站,有一个MySQL数据库 127.0.0.1:3306, 那么在一个进程中无论我们需要进行多少次针对改数据库的操作,都只需要连接数据库一次,使用相同的数据库连接句柄(MySQL Connection Resource),从业务需求上来看就只需要一个实例。

相反,同样以购物网站为例,存在许多商品,这些商品都不一样(id,name,price..),这个时候需要显示一个商品列表,加入我们建立一个 Product 作为数据映射对象,那么从业务需求上来说,一个实例就无法满足业务需求,因为每个商品都不一样。

2. 不断new操作增加不必要的资源消耗

我们一般会在类的构造方法(new操作肯定会调用)中进行一些业务操作,例如数据库连接对象可能会在构造方法中尝试读取数据库配置并进行数据库连接(如mysqli::__construct())、日志写入对象会判断日志写入目录是否存在并写入(不存在可能尝试创建改目录)、全局配置解析对象可能需要定位配置文件的保存目录并进行文件扫描等。

这些业务都会消耗相当的资源,如果在一个进程中我们值需要做一次,将会非常有利于我们提高应用的运行效率。

3. 全局调用便利

因为单例模式的一大特点就是通过静态方法获取对象实例,那么就意味着访问对象的方法时不需要先new一个对象的实例,如果改对象需要很多地方使用,则提高了调用的便利性。

通过一个日志操作类来举例:

 代码如下 复制代码

class Logger{

    //首先,需要一个私有的静态变量来存储产生的对象实例
    private static $instance;

    //业务变量,保存日志写入路径
    private $logDir;

    //构造方法,注意必须也是私有的,不允许被外部实例化(即在外部被new)
    private function __construct(){
        //调试输出,测试对象被new的次数
        echo "new Logger instance rn";
        $logDir = sys_get_temp_dir(). DIRECTORY_SEPARATOR . "logs";
        if(!is_dir($logDir) || !file_exists($logDir)){
            @mkdir($logDir);
        }
        $this->logDir = $logDir;

    }

    //类唯一实例的全局访问点,用于判断并返回对象实例,供外部调用
    public static function getInstance(){
        if(is_null(self::$instance)){
            $class = __CLASS__; //获取本对象的类型,也可以用new self()方式
            self::$instance = new $class();
        }
        return self::$instance;
    }

    //重载__clone()方法,不允许对象对克隆
    public function __clone(){
        throw new Exception("Singleton Class Can Not Be Cloned");
    }

    //具体的业务方法,实际可以有很多方法
    public function logError($message){
        $logFile = $this->logDir . DIRECTORY_SEPARATOR . "error.log";
        error_log($message, 3, $logFile);
    }
}

//日志调用
$logger = Logger::getInstance();
$logger->logError("An error occured");
$logger->logError("Another error occured");

//或者这样调用
Logger::getInstance()->logError("Still have error");
Logger::getInstance()->logError("I should fix it");


在单例模式中可能遇到一种比较特殊的情况,比如数据库连接对象,对于大型应用来说,很可能需要连接多台数据库,那么不同的数据库公用一个对象可能会产生问题,比如连接的分配、获取insert_id,last_error等。这个问题也比较好解决,就是把我们的$instance变量变成一个关联数组,通过给getInstance方法传入不同的参数获取不同的"单例对象"(引号的含义是:严格来说类可能被new多次,但是这个new也是在我们的控制之内的,而不是在类外部):

 代码如下 复制代码

class MysqlServer{
    //注意,变成复数了哦^_^  当然只是为了标识而已
    private static $instances = array();

    //业务变量,保持当前实例的mysqli对象
    private $conn;

    //显著特征:私有的构造方法,避免在类外部被实例化
    private function __construct($host, $username, $password, $dbname, $port){
        $this->conn = new mysqli($host, $username, $password, $dbname, $port);
    }

    //类唯一实例的全局访问点
    public static function getInstance($host='localhost', $username='root', $password='123456', $dbname='mydb', $port='3306'){
        $key = "{$host}:{$port}:{$username}:{$dbname}";
        if (empty(self::$instances[$key])){
            //这里也可以用 new self(); 的方式
            $class = __CLASS__;
            self::$instances[$key] = new $class($host, $username, $password, $dbname, $port);
        }
        return self::$instances[$key];
    }

    //重载__clone方法,不允许对象实例被克隆
    public function __clone(){
        throw new Exception("Singleton Class Can Not Be Cloned");
    }

    //查询业务方法,后面省略其它业务方法
    public function query($sql){
        return $this->conn->query($sql);
    }

    //尽早释放资源
    public function __destruct(){
        $this->conn->close();
    }
}


问题1:单例类能否拥有子类,因为单例类的构造方法是私有的,因此无法被继承,如果要继承则需要将构造方法改为protected或public,这就违背了单例模式的本意。因此,如果你想给单例类加子类,那就需要回头想想是否错用了模式,或者结构设计上有问题。

问题2:单例滥用,单例模式相对来说比较好理解和实现,因此一旦认识到单例模式的好处,很可能什么类都想写成单例,因此在使用次模式之前一定要考虑上述3种情况,看是否真的有必要使用。

 

标签:[!--infotagslink--]

您可能感兴趣的文章: