webpage to statistic OTRS time

最近好无聊啊,被老板要求统计OTRS里面所用的时间,OTRS本身的PDF报靠可读性不是很友好,而且,这个时间统计本身是不支持的,就开始自己动手写一个了。。。

由于SQL比较长,我就先做了几个视图。。。

time_stats视图(所有时间):

CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `time_stats` AS select concat(`u`.`first_name`,' ',`u`.`last_name`) AS `name`,`u`.`id` AS `uid`,`tt`.`name` AS `type`,`tt`.`id` AS `tid`,sum(`ta`.`time_unit`) AS `minutes` from (((`time_accounting` `ta` join `users` `u`) join `ticket` `t`) join `ticket_type` `tt`) where ((`ta`.`change_by` = `u`.`id`) and (`ta`.`ticket_id` = `t`.`id`) and (`t`.`type_id` = `tt`.`id`)) group by `u`.`id`,`t`.`type_id`

time_stats_3mons视图(最近三个月内):

CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `time_stats_3mons` AS select concat(`u`.`first_name`,' ',`u`.`last_name`) AS `name`,`u`.`id` AS `uid`,`tt`.`name` AS `type`,`tt`.`id` AS `tid`,sum(`ta`.`time_unit`) AS `minutes` from (((`time_accounting` `ta` join `users` `u`) join `ticket` `t`) join `ticket_type` `tt`) where ((`ta`.`change_by` = `u`.`id`) and (`ta`.`ticket_id` = `t`.`id`) and (`t`.`type_id` = `tt`.`id`) and (`ta`.`create_time` between (now() - interval 3 month) and now())) group by `u`.`id`,`t`.`type_id`

time_stats_6mons视图(最近6个月内):

CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `time_stats_6mons` AS select concat(`u`.`first_name`,' ',`u`.`last_name`) AS `name`,`u`.`id` AS `uid`,`tt`.`name` AS `type`,`tt`.`id` AS `tid`,sum(`ta`.`time_unit`) AS `minutes` from (((`time_accounting` `ta` join `users` `u`) join `ticket` `t`) join `ticket_type` `tt`) where ((`ta`.`change_by` = `u`.`id`) and (`ta`.`ticket_id` = `t`.`id`) and (`t`.`type_id` = `tt`.`id`) and (`ta`.`create_time` between (now() - interval 6 month) and now())) group by `u`.`id`,`t`.`type_id`

time_stats_lastmon视图(上个月):

CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `time_stats_lastmon` AS select concat(`u`.`first_name`,' ',`u`.`last_name`) AS `name`,`u`.`id` AS `uid`,`tt`.`name` AS `type`,`tt`.`id` AS `tid`,sum(`ta`.`time_unit`) AS `minutes` from (((`time_accounting` `ta` join `users` `u`) join `ticket` `t`) join `ticket_type` `tt`) where ((`ta`.`change_by` = `u`.`id`) and (`ta`.`ticket_id` = `t`.`id`) and (`t`.`type_id` = `tt`.`id`) and (date_format(`ta`.`create_time`,'%y-%m') = date_format((curdate() - interval 1 month),'%y-%m'))) group by `u`.`id`,`t`.`type_id`

time_stats_lastweek视图(上周):

CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `time_stats_lastweek` AS select concat(`u`.`first_name`,' ',`u`.`last_name`) AS `name`,`u`.`id` AS `uid`,`tt`.`name` AS `type`,`tt`.`id` AS `tid`,sum(`ta`.`time_unit`) AS `minutes` from (((`time_accounting` `ta` join `users` `u`) join `ticket` `t`) join `ticket_type` `tt`) where ((`ta`.`change_by` = `u`.`id`) and (`ta`.`ticket_id` = `t`.`id`) and (`t`.`type_id` = `tt`.`id`) and (yearweek(`ta`.`create_time`,0) = (yearweek(now(),0) - 1))) group by `u`.`id`,`t`.`type_id`

time_stats_thismon视图(本月):

CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `time_stats_thismon` AS select concat(`u`.`first_name`,' ',`u`.`last_name`) AS `name`,`u`.`id` AS `uid`,`tt`.`name` AS `type`,`tt`.`id` AS `tid`,sum(`ta`.`time_unit`) AS `minutes` from (((`time_accounting` `ta` join `users` `u`) join `ticket` `t`) join `ticket_type` `tt`) where ((`ta`.`change_by` = `u`.`id`) and (`ta`.`ticket_id` = `t`.`id`) and (`t`.`type_id` = `tt`.`id`) and (date_format(`ta`.`create_time`,'%y-%m') = date_format(now(),'%y-%m'))) group by `u`.`id`,`t`.`type_id`

time_stats_thisweek视图(本周):

CREATE ALGORITHM=UNDEFINED DEFINER=`root`@`localhost` SQL SECURITY DEFINER VIEW `time_stats_thismon` AS select concat(`u`.`first_name`,' ',`u`.`last_name`) AS `name`,`u`.`id` AS `uid`,`tt`.`name` AS `type`,`tt`.`id` AS `tid`,sum(`ta`.`time_unit`) AS `minutes` from (((`time_accounting` `ta` join `users` `u`) join `ticket` `t`) join `ticket_type` `tt`) where ((`ta`.`change_by` = `u`.`id`) and (`ta`.`ticket_id` = `t`.`id`) and (`t`.`type_id` = `tt`.`id`) and (date_format(`ta`.`create_time`,'%y-%m') = date_format(now(),'%y-%m'))) group by `u`.`id`,`t`.`type_id`

然后就是php代码。。。。

<?php
        $remote_ip = $_SERVER["REMOTE_ADDR"];
        $page = $_SERVER["SCRIPT_NAME"];
        $ips=array(
                        '10.0.0.1',        //Sample King IP
                        '10.0.0.2',      //Brutex IP
                        '10.0.0.3',
                );
        if(!in_array($remote_ip,$ips)){
                die("<h1>Permession Denied!</h1>");
        }
?>


<?php

        echo "<!DOCTYPE html>\n";
        echo "<html>\n";
        echo "<head>\n";
        echo "<title>OTRS Time Stats</title>\n";
        echo "<style>\ntable,th,td\n{\n\tborder:1px solid black;\n\tborder-collapse:collapse\n}\n</style>\n";
        echo "</head>\n";
        echo "<body>\n";

?>

<?php
        $times = array(
                        "time_stats_thisweek" => "This week",
                        "time_stats_lastweek" => "Last week",
                        "time_stats_thismon" => "This month",
                        "time_stats_lastmon" => "Last month",
                        "time_stats_3mons" => "Latest 3 months",
                        "time_stats_6mons" => "Latest 6 months",
                        "time_stats" => "All time",
                );

        $timeperiod = $_POST['timeperiod'];
        if(!array_key_exists($timeperiod,$times)){
                echo "<h2>Select a time period you want to query:</h2>\n";
                echo "<form action=\"$page\" method=\"post\">\n";
                echo "<select name=\"timeperiod\">\n";
                foreach($times as $key => $val){
                        echo "\t\t<option value=\"$key\">".$val."</option>\n";
                }
                echo "\t</select>\n";
                echo "<input type=submit>\n</form>";
        }else{
?>

<?php

        $tablename = $timeperiod;

        $conn = @mysql_connect("localhost","readonly","readonly") or die("Cannot connect to DB");
        mysql_select_db("otrs",$conn);
        $user_list = mysql_query("select distinct name from $tablename order by uid",$conn);
        while($row = mysql_fetch_array($user_list)){
                //$newuids[] = $row['uid'];
                $newusers[] = $row['name'];
        }
        $type_list = mysql_query("select distinct type,tid from $tablename order by tid",$conn);
        while($row = mysql_fetch_array($type_list)){
                $newtids[] = $row['tid'];
                $newtypes[] = $row['type'];
        }

        echo "<h3>Time Statistics for <em><font color=red>".$times["$tablename"]."</font></em></h3>\n";
        echo "<table border=1>\n\t<tr><td>&nbsp;</td>";
        foreach($newtypes as $val){
                echo "<td>".$val."</td>";
        }
        echo "<td><b>Sum</b></td></tr>\n";

        foreach($newusers as $val){
                echo "\t<tr><td>$val</td>";
                $timesum = 0;
                foreach($newtids as $val2){
                        $time_res = mysql_query("select minutes from $tablename where tid=$val2 and name='$val'",$conn);
                        #$time_res = mysql_query("select round(minutes/60,1) as minutes from $tablename where tid=$val2 and name='$val'",$conn);
                        if(!time_res){
                                echo "<td>&nbsp;</td>";
                        }else{
                                $time = mysql_result($time_res,0);
                                echo "<td>".round($time/60,1)."</td>";
                                $timesum = $timesum+$time;
                        }
                }
                echo "<td>".round($timesum/60,1)."</td></tr>\n";
        }

        echo "\t<tr><td><b>Total</b></td>";
        foreach($newtids as $val){
                $time_res = mysql_query("select round(sum(minutes)/60,1) as minutes from $tablename where tid=$val",$conn);
                if(!time_res){
                        echo "<td>&nbsp;</td>";
                }else{
                        $time = mysql_result($time_res,0);
                        echo "<td>".$time."</td>";
                }
        }
        $timesum_res = mysql_query("select round(sum(minutes)/60,1) as minutes from $tablename",$conn);
        $timesum = mysql_result($timesum_res,0);
        echo "<td>".$timesum."</td></tr>\n";

        echo "</table>\n";
        echo "<br>\n";
        echo "<div><a href=\"".$page."\">Back</a></div>\n";
        mysql_close($conn);
?>

<?php
        }
?>
<?php
        echo "</body>\n";
        echo "</html>\n";
?>

php script to monitor OTRS queue size from SNMP

最近公司上线OTRS,感觉还不错,顾问居然还给了数据库的结构图,闲下来就写了这个php脚本给Opsview用来监控OTRS支持队列的大小。别问我为什么用php…因为我实在是不会pel….

测试环境:

DISTRIB_ID=Ubuntu
DISTRIB_RELEASE=12.04
DISTRIB_CODENAME=precise
DISTRIB_DESCRIPTION="Ubuntu 12.04.4 LTS"

废话不说,先帖脚本:

#!/usr/bin/php
<?php

# Tomas Tang on 18/02/2014
# Check the OTRS support queue size

# Disable error report
error_reporting(0);

# get arguments
$procname = $argv[0];
$queuename = $argv[1];
$warnlevel = $argv[2];
$critilevel = $argv[3];

# keep it for future develop
#$QUEUE = array(
#               "allnew",
#               "escalated",
#               "second_level_support",
#               "first_level_support",
#);


# set query SQL and help
if("$queuename"=='allnew'){
        # all the tickets with state new but not in delete queue
        $sql = "select count(1) from ticket where ticket_state_id=1 and queue_id!=3;";
}elseif("$queuename"=='escalated'){
        # not in use yet, to be finished
        $sql = "select count(1) from ticket where ticket_state_id=1 and queue_id!=3;";
}elseif("$queuename"=='first_level_support'){
        # all tickets which are not (pending to) closed
        $sql = "select count(1) from ticket where ticket_state_id in (1,4,6,11) and queue_id=5;";
}elseif("$queuename"=='second_level_support'){
        # all tickets which are not (pending to) closed
        $sql = "select count(1) from ticket where ticket_state_id in (1,4,6,11) and queue_id=6;";
}else{
        echo "Usage: $procname  <QueueName>  <WarnNumber>  <CriticalNumber>\n";
        echo "      QueueName:      Queueu name to query, right now only in \"allnew\",\"escalated\",\"first_level_support\" and \"second_level_support\"\n";
        echo "      WarnNumber:     Tickets quantity start to be warn, required\n";
        echo "      CriticalNumber: Tickets quantity start to be critical, must greater than WarnNumber, required\n";
        exit(3);
}

# Double check query SQL
if(empty($sql)){
        echo "UNKNOWN - Unknown error\n";
        exit(3);
}

# Check arguments again.
if(!is_numeric("$warnlevel")||!is_numeric("$critilevel")){
        echo "UNKNOWN - Incorrect arguments.\n";
        exit(3);
}elseif($warnlevel>=$critilevel){
        echo "UNKNOWN - Incorrect warn/critical level.\n";
        exit(3);
}

# connect to database
$conn = @mysql_connect("localhost","readonly","readonly") or die("Cannot connect to DB");
mysql_select_db("otrs",$conn);

# fetch data
$result = mysql_query("$sql",$conn) or die("Query failed");
$result = mysql_result($result,0);

# close db
mysql_close($conn);

if ($result>=$critilevel){
        echo "CRITICAL - Queue size is $result, queue is huge!!!\n";
        exit(2);
}elseif($result>=$warnlevel){
        echo "WARN - Queue size is $result, queue is big!\n";
        exit(1);
}else{
        echo "OK - Queue size is $result, queue is OK.\n";
        exit(0);
}

?>

脚本本身没什么好看的,不过最开始用来传参的东西还是蛮好玩的,这种脚本不能跟在web里面一直的传参,只能通过这个叫$argv的数组。

把脚本保存为

/usr/local/bin/check_otrs_queue

修改/etc/snmp/snmpd.conf,加上下面几行

exec otrs_new_tickets /usr/local/bin/check_otrs_queue allnew 15 20
exec first_level_support /usr/local/bin/check_otrs_queue first_level_support 30 50
exec second_level_support /usr/local/bin/check_otrs_queue second_level_support 10 15

最后就是使用check_snmp_exec.sh检测了~~~

Zend Optimizer 3.3.3 is incompatible with XCache 1.2.2 in Unknown on line 0

想在服务器上同时使用Zend Optimizer与Xcache时遇到的问题

PHP Fatal error: [Zend Optimizer] Zend Optimizer 3.3.3 is incompatible with XCache 1.2.2 in Unknown on line 0

原因: Zend主动蔽屏其他一些插件,xcache偏在其内

解决方法:把xcache的配置写在zend配置的前面即可

来源:http://xcache.lighttpd.net/ticket/200

为phpwind做代理加速镜像

今天给风云墙做了一个教育网的代理服务器来给教育网的用户加速。本来以为是一个很简单的问题,结果却大费周折。

第一打算是用squid来做,结果却由于原来的80端口被占用,暂时找不到一个圆满的解决方案,只好放弃。

80端口已经被apache占用了,也就只好用mod_proxy来做了。
在apache中加上这么一个vhost,理论上应该是可以了,但是,里面的链接还是指向原来的http://bbs.clwind.net,并不像反向代理所期待的http://edu.clwind.net.

<VirtualHost *:80>
    ServerAdmin myhnet@gmail.com
    DocumentRoot /none
    ServerName  edu.clwind.net
    ProxyRequests Off
    ProxyPass  / http://bbs.clwind.net
    ProxyPassReverse / http://bbs.clwind.net
</VirtualHost>

开始一直以为是反向代理的问题(我对反向代理不太熟悉),查找了好久,也没发现问题所在(本来就不是他的问题,怎么可能发现得了)。最好做了一个最简单的网站来做源站,才发现原来是phpwind的head部分的问题。

在phpwind的header.html中,给页面加上了一个base标签

<base id="headbase" href="$db_bbsurl/" />

base标签的作用是给网页中的链接指定一个默认的URL前缀或者是指定一个target,比如:

<base target="_blank" />

而在phpwind中,$db_bbsurl这个变量是由PHP系统变量$_SERVER[HTTP_HOST]得来的。

但是这个变量在使用了反向代理之后,并不是我们访问的URL,这个时候介入了一个新的变量,只有在使用代理访问之后才会有的变量:$_SERVER[HTTP_X_FORWARDED_HOST]。这个变量才是我们访问的URL。

这样,为了反向代理能够正常使用,我们需要更改phpwind的代码。
打开global.php

解决base标签的问题
找到:

$R_url = $db_bbsurl = Char_cv("http://$_SERVER[HTTP_HOST]".substr($tmp,0,strrpos($tmp,'/')));

修改为:

if ($_SERVER[HTTP_X_FORWARDED_HOST]) {
        $R_url = $db_bbsurl = Char_cv("http://$_SERVER[HTTP_X_FORWARDED_HOST]".substr($tmp,0,strrpos($tmp,'/')));
} else {
        $R_url = $db_bbsurl = Char_cv("http://$_SERVER[HTTP_HOST]".substr($tmp,0,strrpos($tmp,'/')));
}

解决前台发帖的非法操作问题
同样在global.php中:
找到:

list($http_host) = explode(':',$_SERVER['HTTP_HOST']);

修改为:

if ($_SERVER[HTTP_X_FORWARDED_HOST]){
                        list($http_host) = explode(':',$_SERVER['HTTP_X_FORWARDED_HOST']);
                } else {
                        list($http_host) = explode(':',$_SERVER['HTTP_HOST']);
                }

解决多重代理IP unknow问题
还是global.php
找到:

$onlineip = $_SERVER['HTTP_X_FORWARDED_FOR'];

改为:

$ip_temp=explode(",",$_SERVER['HTTP_X_FORWARDED_FOR']);
        $onlineip = $ip_temp[0];

这样子做有一个BUG:如果访问者用内网代理,得到的IP将会是内网IP。我正在想办法解决。

最后,要做的就是解决后台操作非法的问题。由于有我前面说的那个BUG,我不建议修改这个,可以说明的就是修改的方法跟前台类似。

我的phpwind上传附件大小怎么总是为0K?

今天风云墙的管理给我报一个错误,说论坛上传的附件大小总是0K,也不报错

听到这个,我想到的第一件事就是,是不是附件文件夹被取消了写入的权限,但是,检查后发现写入权限是正确的。

然后以为是网站分区空间用完了,于是用df一看

网站分区的空间倒是没有用完

倒是系统分区的空间用完了,主要是被apache 的日志文件给塞满了

清理一下,然后再试

果然就可以了

难道PHPWIND上传文件要用到/tmp分区吗?很奇怪的一个事情,改天有时间验证一下

今天没有时间了

php中,require(), require_once(), include(), include_once()之间的区别

以前,一直搞不清楚这四个函数之间的区别,今天总算把他们弄明白了。这四个函数,可以说基本上是相同的,只是有一些很细微的差别。

首先,讲一下require()与include()之间区别。
require()与include()之间唯一的区别就是,当引用的文件不存在时,require()在给出错误信息后终止解析,而include()在给出错误信息后,继续后面的解析。换句话说,include()较require()而言,只是给了一个警告。所以,require()一般可以用来引用必需的文件,而include()一般可以用来引用非必需的文件。

而require_once(),include_once与require(),include()的区别只在于,once会检测文件是否加载,如果已经加载则不会重复加载,而没有once的,会直接加载。这样的话如果用没有once的,可能会出现重复加载同一个文件,而可能会导致重复定义函数,或者重复赋值等。

PW强制只能发悬赏帖

这个插件原来我是做过的,但是后来给其他的管理升级时给冲了

现在他们又想要这个功能只好重新再搞了。还好原来的东西还在,花了点时候马上就搞好了

还加了一个功能就是只能发悬赏帖。

呵呵

插件的东西功能就是;

增加了版主对悬赏帖的控制

增加了只能悬赏money的限制

某个区只能发悬赏帖

附件是改动的文件(将后缀改为.rar后解压即可,郁闷自己的blog都不让传这种文件,但好好检查一下设置了),请根据自己需要进行更改,请不要直接覆盖你的原文件

附件:
悬赏帖插件改进

奇怪的php5.2.4

昨天装上5.2.4的windows的zip包,却发现_SERVER[“PHP_SELF”]等一系列的函数值返回不正确
具体表现在所有的返回值都重复了
不知道是php5.2.4的问题还是我的配置问题
如果是php5.2.4的问题,为什么网上都没有人说到这个问题
如果是我的配置问题,那到底应该要怎么样配置啊
用默认的配置没有用

试了下php4.4.7没有问题
想下截别的比较经典的版本测试下,
可惜网官方上似乎没有提供下载

继续努力中

接着写
应该是5.2.4的版本问题,
改装5.2.2,只改动了cgi.force_redirect的值,就OK了
然后,把5.2.4中的mysql模块复制到5.2.2的文件夹当中,
5.2.2的mysql就成了5.0.45了,本来好像是5.0.34。
呵呵

呵呵,向PHP反映一下吧