使用PHPUnit编写PHP单元测试的方法

局限于Java的testng在eclipse中非常强大的手动单测方法这个框框,我试图一直给eclipse安装PHP的测试框架,却发现一直出问题,最后才发觉,PHPUnit的单测思想是直接的脚本测试PHP文件,避免手工的操作。

测试本来就应该自动化,不是吗?所以我接受了PHPUnit的命令行测试方法,而不是在eclipse中手动的右键运行测试。

PHPUnit官网:https://phpunit.de/

使用方法在文档中很明确,加以补充:

1、将PHP的安装目录,加入到Windows的PATH环境变量中

2、任意的建立一个PHP的二进制文件可执行目录,比如c:\bin

3、将c:\bin加入到Windows的PATH环境变量中

4、下载 https://phar.phpunit.de/phpunit.phar 并将文件保存到 C:\bin\phpunit.phar

5、打开命令行(例如,按 Windows+R » 输入 cmd » ENTER)

6、建立外包覆批处理脚本(最后得到 C:\bin\phpunit.cmd):

C:\Users\username> cd C:\bin
C:\bin> echo @php "%~dp0phpunit.phar" %* > phpunit.cmd
C:\bin> exit

7、新开一个命令行窗口,确认一下可以在任意路径下执行 PHPUnit:

C:\Users\username> phpunit --version
PHPUnit x.y.z by Sebastian Bergmann and contributors.

如果在任意命令行下,执行phpunit不会报错,就说明安装成功了。

做一下测试,编写一个文件,注意下面的namespace和引入PHPUnit的方法:

<?php

namespace mytest;

/**
 * test PHPUnit
 * 
 * @author www.crazyant.net
 *        
 */
class MyTestClass extends \PHPUnit_Framework_TestCase {
    /**
     * Testing the answer to “do you love unit tests?”
     */
    public function testDoYouLoveUnitTests() {
        $love = true;
        $this->assertTrue($love);
    }
}  

这个文件放置在C:\tmp\test_phpunit.php

然后打开命令行,执行以下命令,即可完成测试:

C:\tmp>cd c:\tmp

C:\tmp>phpunit test_phpunit.php
PHPUnit 5.1.3 by Sebastian Bergmann and contributors.

.
/ 1 (100%)

Time: 106 ms, Memory: 9.50Mb

OK (1 test, 1 assertion)

C:\tmp>

既然命令行可以执行测试,那么当然很方便的将测试命令都写到一个自动化的.bat或者.bash文件中,每次开发完成,执行全量的自动测试即可。

PHPUnit官网地址:https://phpunit.de/documentation.html

 

本文地址:http://crazyant.net/1898.html,转载请注明来源。

[织梦DEDE迁移]读取织梦MySQL生成所有文章链接

广告:本人承接迁移织梦到wordpress的业务.

本文阐述了从织梦的Mysql数据库读取数据表,生成所有文章链接的方法。

本文中使用了封装了Mysql常用函数的一个模块DBUtil,代码见链接

1、确认链接的组成结构

这个信息记录在dede的分类表dede_arctype的namerule字段中;

执行SQL语句:SELECT namerule  FROM dede_arctype;

会看到返回结果都是一个值(一般都没有修改):{typedir}/{Y}/{M}{D}/{aid}.html

这意思是,链接由以下字段组成:

  • {typedir}:类型的目录,来源于dede_arctype的typedir字段;
  • {Y}{M}{D}:文章发布的时间,来源于dede_archives表的pubdate字段;
  • {aid}:文章ID,来源于dede_archives的ID字段;

2、读取Mysql,拼凑URL

大致过程:

  • 读取mysql的dede_arctype表和dede_archives,得到所有链接信息(包括文章ID、类型名称、类型目录、标题、发布日期、自定义文件名)
  • 对于每一个链接,根据第1步骤的介绍装备链接;
  • 至此已经拿到了所有的链接ID、链接标题和链接URL。
# -*- encoding:utf8 -*-
from common import DBUtil
import pprint
import datetime

dbUtil = DBUtil.DB('127.0.0.1',3306,'root','','oiayafnq_lwqn')

site_home_url = "http://crazyant.net"

class Link():
    def __init__(self, p_linkid, p_title, p_linkurl):
        self.linkid=p_linkid
        self.title=p_title
        self.linkurl=p_linkurl

    def __str__(self):
        strv="%s\n%s\n%s\n"%(self.linkid,self.title,self.linkurl)
        return strv

class DedeLinks():
    def __init__(self):
        self.allLinks=[]

    def getDbArticlesInfo(self):
        '''
                        获取数据库中链接的信息以及对应的分类
        '''
        rs = dbUtil.query('''
                    SELECT 
                        dede_archives.id,dede_arctype.typename,dede_arctype.typedir,typeid,title,pubdate,filename
                    FROM 
                        dede_archives,dede_arctype 
                    WHERE dede_archives.typeid=dede_arctype.id;
                ''')
        return rs

    def equipLink(self, typedir, urldate, filename, linkid):
        '''
                        根据分类目录、发布文章日期、自定义连接名(可以为空),链接ID,拼接成一个URL
        '''
        article_date=str(datetime.date.fromtimestamp(urldate)).replace("-","")
        #print filename
        link_dir = "%s/%s/%s"%(typedir,article_date[:4],article_date[4:])
        if filename.strip()!="":
            link = "%s/%s.html"%(link_dir,filename)
        else:
            link = "%s/%s.html"%(link_dir,linkid)
        link = link.replace("{cmspath}",site_home_url)
        return link

    def getAllDedeLinks(self):
        rs = self.getDbArticlesInfo()
        for row in rs:
            (linkid,typename,typedir,typeid,title,pubdate,filename) = row
            linkurl =self.equipLink(typedir, pubdate, filename, linkid)
            linkNode = Link(linkid, title, linkurl)
            self.allLinks.append(linkNode)

    def process(self):
        self.getAllDedeLinks()

if __name__=="__main__":
    dlinks = DedeLinks()
    dlinks.process()
    for linkNode in dlinks.allLinks:
        print linkNode

其他模块可以访问该模块,采用dlinks.allLinks来访问所有的链接,其中的每个列表元素均包括链接ID、链接标题和链接URL。

转载请注明来源:织梦dede迁移读取织梦mysql生成所有文章链接

 

Magento获取指定分类下的所有子分类信息

二次开发中经常遇到一种情况,就是判断一个分类是否属于某一个大的分类,而大的分类包括很多子分类成树状结构,基本的方法都是先获取大分类下的所有子分类的信息,然后再挨个比较看是否有ID和待定ID相等。一种用递归方法获取大分类所有的ID;第二种用队列等非递归的方法获取所有子分类ID,第二种明显性能要好一些。

本文在magento的模板文件里测试成功一个函数:输入一个分类的ID,将返回该分类下所有子分类(递归获取)的ID,组成一个数组返回。所用的方法为用队列实现的非递归方法:

/**
* 输入:某一个分类的ID数字
* 返回: 该分类下所有子分类的ID组成的数组
* 可用于: 模板文件中可以直接使用,也可以用于action等文件类内部
* 实现思路:使用队列的方法实现非递归,对树从上往下遍历
**/
function getAllChildrenOfCategory($cateid){
    $resArr = array();//结果数组
    $queueArr = array();//队列数组
    array_push($queueArr,$cateid);
    
    while($currentcid = array_pop($queueArr)){
        array_push($resArr,$currentcid);                                            
        //处理当前节点的孩子节点
        $_category = Mage::getModel('catalog/category')->load($currentcid);
        $subcats = $_category->getChildren();
        
        $idarrs = explode(',',$subcats);
        foreach($idarrs as $subCatid){
            if(!$subCatid) continue;
            $_subcategory = Mage::getModel('catalog/category')->load($subCatid);
            if($_subcategory->getIsActive()) {
                array_push($queueArr,$subCatid);
            }
        }
        reset($queueArr);
    }
    return $resArr;
}
//测试一下
$allProducerIds = getAllChildrenOfCategory(19);
$allDesignedIds = getAllChildrenOfCategory(18);

 

PHP没有栈和队列的数据结构,可以用数组来模拟实现,数组的array_push和array_pop刚好就是这么两个方法,其中因为array_pop每次会改变数组的指针,所以可以在循环的末尾reset一下重置数组。

最后的测试,输入的是两个分类的ID,函数执行结束以后,返回的数组里面就是所有子分类的ID。

织梦DEDECMS简洁蓝色模板免费下载(资讯文章类)

模板信息:该模板是我为另一个网站程序员求职网设计的模板,主要分为首页、文章列表页和文章内容页三个模板

主要基调:蓝色,简洁,朴素

文章页需要安装两个插件:无觅相关文章插件和多说文章评论插件。

可以用于:文章站、资讯站、门户站、图片站

适用版本:织梦DEDECMS 5.7版本、编码是UTF-8

使用方法:将压缩包解压后,另起一个名字,上传到templets目录下面,进织梦后台系统设置,在模板默认风格设置的地方写上模板名字,然后更新全站就可以了。需要安装无觅和多说两个插件。这两个插件我用的很好,极力推荐。

下载地址:http://pan.baidu.com/share/link?shareid=122080&uk=1376935646

继续阅读织梦DEDECMS简洁蓝色模板免费下载(资讯文章类)

PHP对数组的高级遍历和操作处理方法

PHP对数组的处理可以称为该语言最有吸引力的特性之一,它支持70多种数组相关的函数。不论你想翻转一个数组、判断某个值在数组中是否存在、将数组转换成一个字符串还是计算数组的大小,仅仅执行一个现有的函数就可以完成。然而也有一些数组相关的任务对开发者的要求就较高,仅仅知道手册有某个功能是不能解决的,这些任务就需要对PHP的原始特性有一些深入的理解,还需要一些解决问题的想象力。

多维关联数组排序

PHP提供了一些数组排序的函数,比如sort(), ksort(),和asort(),但是却没有提供对多维关联数组的排序。

继续阅读PHP对数组的高级遍历和操作处理方法

使用PHP连接、操纵Memcached的原理和教程

Memcahced开源分布式内存对象缓存系统通过减少数据库的负担,从而能够加速你的web应用。在本文中我将解释怎样实现一个基于Memcahced的缓存系统。

数据库

实例中使用的数据库表包含一个自增的id,一个标题和一个链接字段:

CREATE TABLE demos
(
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(300), 
link VARCHAR(300), 
);

继续阅读使用PHP连接、操纵Memcached的原理和教程

PHP开发者最好的学习资源收集

以下内容翻译自:phpbuilder.comPHP Developer Resources文章。资源全为英文资料,不过英文很多文章确实写的非常好!
当今PHP是开发WEB应用程序最流行的脚本语言之一。由此可以发现internet.com上有非常多的好PHP资源。以下是我们的一些最好的PHP资源,包括一些有特色的教程和一些你可能不知道的离线资源。

有特色的PHP教程

  • 学习PHP
  • 使用PHP处理文件
  • 对PHP的介绍
  • 怎样使用PHP和MYSQL实现搜索功能
  • PHP的类继承
  • 怎样在SQL数据库中直接存储图片
  • PHP的类
  • 使PHP作为一种Shell脚本语言
  • 使用PHP发邮件的时候,怎样防止垃圾邮件

离线资源

  • PHP官方文档
  • Zend引擎
  • PHPDeveloper
  • PHP Weblog

确实有一些好资源,这些关键词可以作为搜索引擎搜索,另外internet.com的PHP模块的文章真的很不错。

其他的一些好资源

http://www.9lessons.info

http://phpacademy.org

PHP和MySQL处理树状、分级、无限分类、分层数据的方法

文章标题中的多个词语表达的其实是一个意思,就是递归分类数据,分级数据非常类似数据结构中的树状结构,即每个节点有自己的孩子节点,孩子结点本身也是父亲节点。这是一个递归、分层形式。可以称之为树形层级数据。

层级数据结构是编程语言中非常普通的一种数据结构,它代表一系列的数据每一项都有一个父亲节点(除了根节点)和其他多个孩子结点。WEB开发人员使用层级数据结构用于非常多的场景,包括内容管理系统CMS、论坛主题、邮件列表,还有电子商务网站的产品分类等。

本文章主要介绍了使用PHP和MYSQL来管理分级数据的方法,在其中将给出两种最流行的分级数据模型:

  • 邻接表模型
  • 嵌套集合模型

PHP创建和解析JSON数据的方法

JSON可以解释为“JavaScript的对象表示方法”,也就是说JSON的概念是来源于JavaScript的,对于WEB开发模式来说,下面这个图大家肯定很熟悉:

2012-8-18 225813

由此可以看到,客户端浏览器和服务器端脚本需要交换数据。对于小数据或无格式数据,直接用简单的POST和GET用字符串方法提交过去就可以,但是一些大型的数据,最好使用有格式的方法交换,比如JSON和XML。

JSON是什么?

JSON一种用于在互联网络中传输超量数据的数据交换格式。虽然在Internet中交换数据XML占主要地位,然而JSON却更加的简单并且适用于轻型的数据。

尽管JSON当初是被JavaScript发明并且用于访问远程数据的,它现在却被广泛适用于各种语言,因为JSON是一种于平台无关的数据格式。

JSON数据的数据类型和实例

JSON支持各种各样的数据类型,包括数字、字符串、布尔值、数组数据甚至对象数据(是一个集合,每个元素都是键:值对形式,使用逗号分隔,并且使用大括号包裹)。

让我们看一个JSON数据的简单例子,该例子表示一个雇员的详细信息:

{“id”:”1″,”name”:”mike”,”country”:”usa”,”office”:[“microsoft”,”oracle”]}

使用PHP创建和解析JSON数据的方法

PHP从5.2.0版本以后提供了JSON扩展来处理JSON数据,通过PHP有两个函数json_encode()json_decode非常方便的对JSON数据进行转换和解析。

首先,让我们看一段PHP用数组创建如上各式的JSON的代码:

$json_data = array ('id'=>1,'name'=>"mike",'country'=>'usa',"office"=>array("microsoft","oracle"));
echo json_encode($json_data);

 

该代码直接产生了JSON数据。现在让我们用PHP将上面的JSON解码:

$json_string='{"id":1,"name":"mike","country":"usa","office":["microsoft","oracle"]} ';
$obj=json_decode($json_string);

 

现在变量$obj包含了使用PHP解析后的JSON数据,你可以使用以下的方法来输出和访问:

echo $obj->name; //displays mike
echo $obj->office[0]; //displays microsoft

 

你猜的没错$obj->office是一个数组,你能够使用PHP的foreach方法遍历它:

foreach($obj->office as $val)
    echo $val;

 

PHP的验证码实现(w3schools推荐)

本文使用PHP一些可用的特性实现了验证码功能。该教程非常的简单,使用可以改变的字体生成了验证码图片,正如我们所了解的,验证码是用于避免垃圾评论或者自动提交的。

本验证码程序的资源:

下载地址

在线演示

captcha_code_file.php

代码:

<?php 
session_start();
//设置: 你可以在这里修改验证码图片的参数
$image_width = 120;
$image_height = 40;
$characters_on_image = 6;
$font = './monofont.ttf'; 

//以下字符将用于验证码中的字符 
//为了避免混淆去掉了数字1和字母i
$possible_letters = '23456789bcdfghjkmnpqrstvwxyz';
$random_dots = 10;
$random_lines = 30;
$captcha_text_color="0x142864";
$captcha_noice_color = "0x142864"; 

$code = ''; 

$i = 0;
while ($i < $characters_on_image) { 
    $code .= substr($possible_letters, mt_rand(0, strlen($possible_letters)-1), 1);
    $i++;
}

$font_size = $image_height * 0.75; 
$image = @imagecreate($image_width, $image_height);

/* 设置背景、文本和干扰的噪点 */ 
$background_color = imagecolorallocate($image, 255, 255, 255);

$arr_text_color = hexrgb($captcha_text_color); 
$text_color = imagecolorallocate($image, $arr_text_color['red'], 
$arr_text_color['green'], $arr_text_color['blue']);

$arr_noice_color = hexrgb($captcha_noice_color); 
$image_noise_color = imagecolorallocate($image, $arr_noice_color['red'], 
$arr_noice_color['green'], $arr_noice_color['blue']);

/* 在背景上随机的生成干扰噪点 */ 
for( $i=0; $i<$random_dots; $i++ ) {
    imagefilledellipse($image, mt_rand(0,$image_width),
    mt_rand(0,$image_height), 2, 3, $image_noise_color);
}

/* 在背景图片上,随机生成线条 */ 
for( $i=0; $i<$random_lines; $i++ ) {
    imageline($image, mt_rand(0,$image_width), mt_rand(0,$image_height),
    mt_rand(0,$image_width), mt_rand(0,$image_height), $image_noise_color);
}

/* 生成一个文本框,然后在里面写生6个字符 */ 
$textbox = imagettfbbox($font_size, 0, $font, $code); 
$x = ($image_width - $textbox[4])/2;
$y = ($image_height - $textbox[5])/2;
imagettftext($image, $font_size, 0, $x, $y, $text_color, $font , $code);

/* 将验证码图片在HTML页面上显示出来 */ 
header('Content-Type: image/jpeg');// 设定图片输出的类型
imagejpeg($image);//显示图片
imagedestroy($image);//销毁图片实例
$_SESSION['6_letters_code'] = $code;

function hexrgb ($hexstr) {
    $int = hexdec($hexstr);

    return array( "red" => 0xFF & ($int >> 0x10),
                "green" => 0xFF & ($int >> 0x8),
                "blue" => 0xFF & $int
    );
}
?>

 

验证验证码正确或错误的方法

验证码图片上的文字被存放到了SESSION 变量里面,验证的时候,我们需要将SESSION 里面的值和用户输入的值进行比较即可。

$_SESSION[6_letters_code] – 存放着验证码的文字值
$_POST[6_letters_code] – 这是用户输入的验证码的内容

index.php代码

包含了HTML, CSS, Javascript and PHP代码:

<?php session_start(); 

if(isset($_REQUEST['Submit'])){ 
    // 服务器端验证的代码
    if(empty($_SESSION['6_letters_code'] ) ||
        strcasecmp($_SESSION['6_letters_code'], $_POST['6_letters_code']) != 0)
    { 
        $msg="验证失败!";
    }else{
        //验证码验证正确,这里放验证成功后的代码
    }
} 
?>
<style type="text/css">
.table {
    font-family:Arial, Helvetica, sans-serif;
    font-size:12px;
    color:#333;
    background-color:#E4E4E4;
}
.table td {
    background-color:#F8F8F8;
}
</style>

<form action="" method="post" name="form1" id="form1" >
  <table width="400" border="0" align="center" cellpadding="5" cellspacing="1" class="table">
    <?php if(isset($msg)){?>
    <tr>
      <td colspan="2" align="center" valign="top"><?php echo $msg;?></td>
    </tr>
    <?php } ?>
    <tr>
      <td align="right" valign="top"> 验证码:</td>
      <td><img src="captcha_code_file.php?rand=<?php echo rand();?>" id='captchaimg'><br>
        <label for='message'>请输入上面的验证码 :</label>
        <br>
        <input id="6_letters_code" name="6_letters_code" type="text">
        <br>
        无法读图片吗?点击 <a href='javascript: refreshCaptcha();'>here</a> 刷新
        </p></td>
    </tr>
    <tr>
      <td> </td>
      <td><input name="Submit" type="submit" onclick="return validate();" value="提交"></td>
    </tr>
  </table>
</form>
<script type='text/javascript'>
function refreshCaptcha()
{
    var img = document.images['captchaimg'];
    img.src = img.src.substring(0,img.src.lastIndexOf("?"))+"?rand="+Math.random()*1000;
}
</script>