最近给单位写了一个内网用的工资条查询页面,结构很简单:财务人员将从集团财务系统中导出的Excel表格上传,处理后为每位员工建立账户(当然已存在的不会重建,重名的也有处理方案,因为和主题无关不详细展开),建立对应年月数据表并填充数据,员工使用账号密码登录后可查看自己的「电子工资条」。做这个东西的初衷据说是财务不愿意打印纸质工资条了,ft。
整套程序中其他部分都是基本的PHP+MySQL流程,唯独如何对Excel表处理是个难点,必须要感谢PHPExcel,使得读取Excel表格不再是最困难的部分。在编写表格读取代码的过程中,还发现了PHP一个有趣的特性:
在处理字符变量的算数运算时,PHP 沿袭了 Perl 的习惯,而非 C 的。例如,在 Perl 中 $a = ‘Z’; $a++; 将把 $a 变成’AA’,而在 C 中,a = ‘Z’; a++; 将把 a 变成 ‘[‘(’Z’ 的 ASCII 值是 90,'[‘ 的 ASCII 值是 91)。注意字符变量只能递增,不能递减,并且只支持纯字母(a-z 和 A-Z)。递增/递减其他字符变量则无效,原字符串没有变化。
——PHP文档《递增/递减运算符》
也就是说,如果要以列为单位递增读取表格中的内容,无需手工编写代码处理列名称(Excel的列名称是A、B、C……AA、AB、AC……XFD之类,不同版本的Excel末列名称不同,但都是1-3个字母的顺序组合),只需要使用类似下面的代码即可:
……
for($col = 'A'; $col < 'ZZ'; $col++) {
$phpExcel_Sheet -> getCell($col.$row);
}
……
一番努力后,程序已可以正确处理财务部早先给出的样表,但是由于本单位的特殊情况,还有另一套工资表要处理,这个版本的工资表格式上与先前的样表无异,只是工资项目比较多,即:先前的样表最大到Z列,而另一版本的最大列为AW。
由于PHP没有简便的方式将关联数组按索引进行读取(话说为啥不支持?),程序中拼合最终入库的数据时是这样处理的:
……
$lastcol = array_keys($xls_itemname)[sizeof($gz_itemname)-1]; //获取末列Key
foreach($xls_data as $data_row) {
for($col = 'E'; $col < $lastcol; $col++) {
$json_array[$xls_itemname[$col]] = $data_row[$col]; //为生成类似 {'基本工资':'800.00', '岗位薪酬':'1000.00',...}这样的JSON做准备
}
$json = json_encode($json_array);
……
}
……
结果,以上代码在处理第一批样表(末列为Z)时工作良好;但到了第二批样表,上传后直接运行超时,将debug信息打印出来,发现虽然$lastcol的值正确取到了AW,但程序在处理到AW列后并未停止,一路飙到了不知道哪里去,直到达到PHP的最大运行时间被掐断为止。
调试了很久都不知所措,最后只好用另一种方式进行临时补救:
……
//不再取$lastcol
foreach($xls_data as $data_row) {
for($col = 'E'; $col < 'ZZ'; $col++) {
if(isset($xls_itemname[$col]) == FALSE) break; //当取到未定义的列名时跳出
……
}
}
……
这种方法的运行效率想必比较低,但是至少可以正常运行。
猜测与PHP特殊的字母递增运算的实现有关系,但是我还是不知道为什么。
注:所有评论将在审核通过后显示,请不要在评论内容的任何位置出现链接,否则您的评论将被自动移入回收站,且永远不会被复审。
All comments will be available after being manually reviewed, please do not include any links anywhere in your comment, otherwise your comment will be automatically deleted and are not eligible for review.