Monthly Archives: November 2013

CodeIgniter遇到了“The filetype you are attempting to upload is not allowed.”的问题

1. 问题的引出 公司内部系统需要上传Word文档,开发用的是CI 2.1.4。 在开发和大部分人的机器上跑得都挺好的,就是有几个人说不能上传文件。查看了一下错误信息,就是: CodeIgniter: “The filetype you are attempting to upload is not allowed.” 检查服务器端的代码: 应该是支持doc和docx格式的文件上传的。 只好打出$_FILES来看看。分别在正常的机器和不正常的机器上尝试上传,发现上传文件的type不一样。 正常机器上传的时候,type是 “application/msword”,而不能正常上传的用户的这个值则为”application/kswps”。 原来如此。 2. 解决方法 解决方法就是修改应用根目录下的config/mimes.php文件,增加doc的Content-Type类型。 其中后面的’application/kswps’是我手工加的。 3. 谁设置了Content-Type 谁设置的mime type,根据什么设置的? 首先来看一下第一个问题的答案,那就是浏览器。 根据PHP的官方记载: $_FILES[‘userfile’][‘type’] 文件的 MIME 类型,如果浏览器提供此信息的话。一个例子是“image/gif”。不过此 MIME 类型在 PHP 端并不检查,因此不要想当然认为有这个值。

Posted in Tech, Web Tagged with: , , ,

在Java中调用OS命令并实现限时执行

1. 背景 最近在做的一个批处理程序,由于历史原因一直使用Java语言,其核心处理是启动若干线程,每个线程通过调用第三方的.exe程序进行数据处理。但是最近发现的一个问题是,有时候这个.exe会一直运行,不会返回,导致所有线程都被阻塞(每个线程内都是等待程序执行完毕的)。 环境:Windows 2008 + Java 1.6 2. 改善 本文中的事例代码都是重新编写的测试用代码,与具体工作无关。测试代码都放到了Github上。 第一次做的改善是增加了超时处理,简单来说就是启动一个Callable对象执行任务,并通过个future.get(timeout,TimeUnit)指定一个超时时间来实现,具体可以参考如下代码(示例中超时时间为10秒钟)。 这段代码里,如果这个线程(SimpleTimeoutTask类)在10秒还没返回的话,就会导致超时异常发生,从而在TimeoutException处理中取消线程的执行。 表面上没什么问题,但是实际上这个future.cancel是很不可靠的,首先,它不能取消正在执行网络I/O等待中的线程的执行,其次,对于本案例中的调用OS命令也无能为例。如果你要使用future.cancel的话,一定要经过充分确认其可靠性才行(本例代码这个cancel会返回true)。 继续上面说的,最后一行调用了threadsPool.shutdownNow ,即使这样,已经启动的程序(本例中为ping.exe)也不会终止。 所以,这时候必须手工杀死这些即将成为“孤儿”的进程。 3. 找到PID 要想杀死一个进程,首先想到的就是找到PID。 3.1. 能从Process对象得到PID么? 答案是不能,严格来说是有点麻烦。 看似简单,然而在Java+Windows下去貌似很难。为什么这么说呢?因为Java标准的Process API没有提供取得PID的方法。 然后去网上搜了一下,发现了java.lang.UNIXProcess(参考Blog ),但是这个实现类在Windows下也不能用。不过根据这篇Blog的记载,应该是在Windows下也有类似的实现才对,原理应该都是通过对底层的实现类通过反射调用native方法的。在这里记载了如何在Windows下通过“Suns JNA Site”取得PID的例子,很不幸的是,JNA的网站貌似不能访问了,也许这个库已经不被支持了。 不想再下载第三方库,更不想碰和JNI相关的东西。所以也放弃了这种方法。 3.2. 通过Windows自带的tasklist来取得被启动程序的进程PID 这种方法简单来说,需要知道要启动程序的映像名(即程序名),比如ping.exe,然后在调用 Runtime.getRuntime().exec()之前,和程序被启动之后,通过tasklist这个Windows自带的命令,来分别取出前后两个进程列表,通过判断列表的变化,来得到哪个进程是新创建的,并返回新创建的进程的PID。 不过这中方法的最大问题是必须要保证程序启动时候的线程安全,而且还要确保其它程序不会创建这样的进程,否则取得的结果肯定是不准确的。 作为示例,我写了一个简单的测试程序,请参考Github代码里的TaskWithPid类 示例代码如下。 由于既要得到PID,还要得到该进程的标准输出,所以上面这段代码主要是取得PID供以后使用,而从Process的流里读出stdout则放到了一个带执行时限的线程里,即waitForTask方法。 在超时发生后,waitForTask()会返回一个null给调用方(当然也可以采取其它方式通知这个方法的调用方执行超时),调用方则可以进行相应的处理。 这种方法虽然笨,但是如果能保证程序没有别的启动入口,而且Runtime.getRuntime().exec()能立即返回(应该不会有例外吧?)的话,应该还算能满足要求的。不过由于实现麻烦,且影响性能(每启动一次应用都需要多调用两次TASKLIST命令),所以我也不打算采用这种方法。

Posted in Tech Tagged with: , , , , , , , , , , , , , , ,

无觅相关文章插件,快速提升流量