手头上的项目已经在收尾了!为了做到多人开发出的所有代码结构清晰,于是写了个过滤文件内容的规则功能,放在svn提交的时候进行判断,不符合规则的拒绝提交,显示出具体某行错误!(整个花了我一天左右的时间,- -!慢了点,正则不熟哈,不过这次正好练了下,好多了!)给大家共享下,欢迎拍砖!
文件规则:
【全局规则】
[1]文件编码方式必须为UTF8
[2]文件中出现的字符只能在范围:
\x{4e00}-\x{9fa5}汉字
\x{3000}-\x{303f}标点
\x{0000}-\x{0070}基本acsii
以及常用的全角标点
[3]头部前三行必须为
<?php
/**
 * @=[CLASS]
其中class取值为LIST、SCRIPT、STATIC、HACK
[4]每行的开头只能为tab或什么都没有
[5]文件每行只能有一个引号外的';'号【LIST规则】[1]五段分明,某些段可为空,但需要保留段注释
[2]不超过200行,不计注释和空行【SCRIPT规则】
[1]四段分明,某些段可为空,但需要保留段注释
[2]不超过1000行,不计注释和空行【STATIC规则】
[1]所有方法必须为静态方法,public或者private
[2]不超过1000行,不计注释和空行
[3]函数注释【HACK规则】
无规则代码如下:<?php
/**
 * @=STATIC
 * 
 * 针对文件内容规则的检测
 * @author yichen
 * @history 2010-11-02
 *  
 */class CK_coding{
    
    
    /***用于数据量大的文件***/
    public static function readLine($path, $line_num, $delimiter="\n")
    {
        /***设置读取一行***/
        $i = 1;
    
        /***读取模式打开文件***/
        $fp = fopen( $path, 'r' );
    
        /*** 循环读取 ***/
        while ( !feof ( $fp) )
        {
            /*** 读取一行内容到内存中 ***/
            $buffer = stream_get_line( $fp, 1024, $delimiter );
            /*** 假如到达查找的那一行 ***/
            if( $i == $line_num )
            {
                /*** 返回在内存中那一行的内容 ***/
                return str_replace(array("\n","\r"),'',$buffer);
            }
            $i++;
            /*** 清除内存 ***/
            $buffer = '';
        }
        return false;
    }
    
    
    /***用于数据量小的文件***/
    public static function getline($ct,$num=1){
        $x = split("\n",$ct);
        $num--;
        return str_replace(array("\n","\r"),'',$x[$num]);
    }    /***判断是否是utf-8编码***/
    public static function utf8char($ct)
    {
        return ($ct === mb_convert_encoding(mb_convert_encoding($ct, "UTF-32", "UTF-8"), "UTF-8", "UTF-32"))? true : false;
    }
    
    
    /*****文件中出现的字符只能在范围:\x{4e00}-\x{9fa5}汉字  \x{3000}-\x{303f}标点  \x{0000}-\x{0070}基本acsii *******/
    public static function ctchar($ct){
        if(!preg_match("/^([\x{4e00}-\x{9fa5}]|[\x{3000}-\x{303f}]|[\x{0000}-\x{0070}]|[a-zA-Z]|[\{\}\:\(\)\《\》\——\;\,\。\“\”\<\>])+$/u",$ct)){return false;} 
        //if(!preg_match("/^[\x{4e00}-\x{9fa5}\x{3000}-\x{303f}\x{0000}-\x{0070}a-zA-Z\(\)\《\》\——\;\,\。\“\”\<\>]+$/u",$ct)){return false;}
        return true;
    }
    
    public static function getlinenum($ct){
        $x = split("\n",$ct);
        return count($x);
    }
    
    
    /***检测程序行开头***/
    public static function ckstline($ct,$num=1){
        $line = str_replace("\t",'',$ct);
        if(!preg_match("/^\S+/",$line)){
            exit("第{$num}行开头存在空格");
        }
    }
    
    
    /***文件每行只能有一个引号外的';'号***/
    public static function ($line){
        $num1 = substr_count($line,';');
        preg_match("/.*\".*\;+\"/",$line,$match1);
        preg_match("/.*\'.*\;+\'/",$line,$match2);
        $num2 = count($match1)+count($match2);
        //echo($num1.'-'.count($match1).'-'.count($match2).'<br>');
        if(($num1-$num2)>1){return false;}
        return true;
    }
    
    /***检测文件行数限制规则***/
    public static function numrule($tp,$num,$ct){
        switch ($tp)
        {
        case 'LIST':
            if($num>200){exit('LIST类型代码行数不能超过200');} 
            break;
        case 'SCRIPT':
            if($num>1000){exit('SCRIPT类型代码行数不能超过1000');}
            break;
        case 'STATIC':
            if($num>1000){exit('STATIC类型代码行数不能超过1000');}
            break;
        case 'HACK':
            
            break;                               
        }
        
        $notenum['LIST'] = 5;
        $notenum['SCRIPT'] = 4;
        preg_match_all("/.*SECT\-+\d{1}\-START+.*/",$ct,$match);
        $countnote = count($match[0]);
        /**SECT-3-START**/
        switch($tp)
        {
        case "LIST":
            if($countnote!=$notenum['LIST']){exit("{$tp}类型必须有{$notenum['LIST']}段注释");}         
            break;
        case "SCRIPT":
            if($countnote!=$notenum['SCRIPT']){exit("{$tp}类型必须有{$notenum['SCRIPT']}段注释");}        
            break;
        case "STATIC":
                    
            break;
        case "HACK":
                        
            break;
        }        
        
        
    }
    
    
    /***检测文件规则***/
    public static function ck($path){
        $ct = file_get_contents($path);
        
        if(!self::utf8char($ct)){
            exit('文件编码方式必须为UTF8');
        }
        if(!self::ctchar($ct)){
            exit('文件中出现的字符超过范围');
        }
        
        
        $line1 = self::getline($ct);
        if($line1!="<?php"){
            exit("文件第一行必须为<?php");
        }
        
        $line2 = self::getline($ct,2);
        if($line2!='/**'){
            exit('文件第二行必须为/**');
        }
        
        
        $line3 = self::getline($ct,3);
        if($line3!=' * @=LIST' && $line3!=' * @=SCRIPT' && $line3!=' * @=STATIC' && $line3!=' * @=HACK'){exit('文件第三行不符合格式');}
        //文件类型
        $filetp = substr($line3,5);
        
        
        
        $num = self::getlinenum($ct);
        $coderow = 0;
        for($i=1;$i<$num+1;$i++){
            $line = self::getline($ct,$i);
            $linect = str_replace(array("\t",' '),'',$line);
            $linect1 = str_replace("\t",'',$line);
            
            
            //只有文件类型为static类型时候才进行注释判断
            if($filetp=='STATIC'){
                if(preg_match("/^([\/\*])+/",$linect)){$note=2;}//如果是注释就标记起来    
            }
            //如果该行为注释或者空则跳过检测
            if(preg_match("/^([\/\*])+/",$linect) || $linect==''){
                continue;
            }else{
                //只有文件类型为static类型时候才进行注释判断
                if($filetp=='STATIC'){
                    if(!preg_match("/^public\s+static\s+function.+/",$linect1)){
                        $note=1;//此行为代码,但不是静态方法
                    }else{
                        ($note==1)? exit("文件第{$i}行错误,请给此静态方法添加注释") : '';//此行为代码,是静态方法    
                    }
                }
            }
            self::ckstline($line,$i);
            if(!self::($line)){exit("文件第{$i}行错误,只能有一个引号外的';'号");}
            $coderow++;//代码行数+1
            
            if(preg_match("/^class\s+\w+\{+$/",$line)){$note=1;}//开始统计注释和静态方法匹配
            
        }
        
        
        self::numrule($filetp,$coderow,$ct);
        
        
    }
}
//调用例子
/***************************
require('ck_coding.php');
CK_coding::ck('static.php');
*****************************/
?>

解决方案 »

  1.   

    想法很好不过....你测试过了吗?至少那个检测分号的部分好像不对啊?下面这个是false? <?phpfunction ($line){
            $num1 = substr_count($line,';');
            preg_match("/.*\".*\;+\"/",$line,$match1);
            preg_match("/.*\'.*\;+\'/",$line,$match2);
            $num2 = count($match1)+count($match2);
            //echo($num1.'-'.count($match1).'-'.count($match2).'<br>');
            if(($num1-$num2)>1){return false;}
            return true;
    }$line='echo "abc;def"; ';
    echo '--'.($line).'--';
      

  2.   

                //如果该行为注释或者空则跳过检测
                if(preg_match("/^([\/\*])+/",$linect) || $linect==''){
                    continue;
                }else{这一段似乎也没有考虑多行注释的情况?
      

  3.   

    $line='echo "abc;def"; ';
    程序只判断单行只能存在一个在引号外的;号!
      

  4.   


    对啊,
    如果有如下注释/****************
     *   what? 
     ***************/的话,
    那么第2,3行你是算作注释还是普通行?
      

  5.   

    你那个检测utf8编码的方法不错~~不过不明白为什么不允许其它字符(非中文/符号/等)出现? 既然已经控制了编码, 有其它字符应该没关系啊
      

  6.   

    关于判断单行只能出现一个完整的语句.也就是说排除代码为for循环的情况(此情况为至少两个引号外的;)下,每行只能有一个在引号外的;号!这个正则我写了好几次还是无法判断全,不知道哪位大虾能出手相助!(引号包括:单引和双引)