昨晚收到留言说那个缩略图插件无法下载,然后测试看了下,居然原来的附件都无法下载了,研究了下,终于发现问题所在。 先说一下 Typecho 附件的数据库设计:
通过查看 TE 的源码发现,TE 的附件信息是以以下方式存放在 contents 表中的:
1 /*
2 /var/Widget/Upload.php
3 line:120
4 */
5 $result = array(
6 'name' => $file['name'],
7 'path' => self::UPLOAD_PATH . '/' . $date->year .'/'. $date->month . '/' . $fileName,
8 'size' => $file['size'],
9 'type' => $ext,
10 'mime' => Typecho_Common::mimeContentType($path)
11 );
12
13 /* ..... ...... */
14
15 /*
16 /var/Widget/Upload.php
17 line:258
18 */
19 $struct = array(
20 'title' => $result['name'],
21 'slug' => $result['name'],
22 'type' => 'attachment',
23 'status' => 'publish',
24 'text' => serialize($result),
25 'allowComment' => 1,
26 'allowPing' => 0,
27 'allowFeed' => 1
28 );
其中 $struct['text']
返回的是序列化的附件信息字符串,其结构如下:
1 return "a:5:{s:4:"name";s:18:"Thumbnail-show.zip";s:4:"path";s:37:"/attachment/2012/01/4f01d62cb3bfc.zip";s:4:"size";i:8513;s:4:"type";s:3:"zip";s:4:"mime";s:15:"application/zip";}";
此字符串的结构为 "数据类型":"长度":"值"
。
注:integer
和 double
直接返回 "数据类型":"值"
。
https://mrasong.com/a/serialize-and-unserialize 关于更多的 serialize
和 unserialize
请参考官方说明。
现在返回正题,TE 本身设计时,上传的附件是按 YYYY/mm/
文件夹存放的,因为个人觉得没什么附件上传,所以就把 /var/Widget/Upload.php
文件中的存放路径修改为 YYYYmm/
直接以月份存放,数据库中原来所有的 YYYY/mm/
路径全部改为 YYYYmm/
,ftp 上附件也迁移了。
理论上,这样是好了,对,是好了,因为新上传的文件没有任何问题,通过 http://host/usr/files/YYYYmm/xxxxxx.xxx
可以直接下载,原来上传的附件也可以通绝对路径下载,但是… 问题还是出现了,我用 Attachment
插件,无法下载。原来的附件,在附件管理中,路径全为 http://mrasong.com
。 问题就出在上面介绍的 serialize
上,serialize
返回的数据中有一个长度,也就是说,改过数据库中附件的 path
但是没有改 path
字符串的长度。
1将 s:38:"/usr/files/201201/4f01d62cb3bfc.zip"
2改为 s:37:"/usr/files/201201/4f01d62cb3bfc.zip"
因为少了一个 "/"
字符串的长度少了 1,到此,问题终于解决了。 总结: Typecho 确实写得非常好,通过研究 TE 的源码,自己也学了不少。顺便感谢下 Mr.Jiang 同学的提醒。