缓存PHP对象到文件的方法?

26
在ASP.NET中,我喜欢Application和Cache存储。它们非常强大。对于未经初始化的人来说,你可以将数据逻辑对象放入其中,然后只需要一次数据库查询即可获得一些数据。
在我转向Linux之后,我放弃了Windows,也放弃了PHP、Python和Ruby作为Webdev开发语言。我使用PHP最多,因为我正在开发几个开源项目,它们都使用PHP。
不用说,我已经探索了PHP在缓存数据对象方面提供的功能。到目前为止,我尝试过以下方法:
1.序列化到文件(一个相当慢/昂贵的过程) 2.将数据写入文件作为JSON/XML/纯文本等(读操作甚至更慢) 3.将数据写入文件作为纯PHP(最快的读取,但写操作相当复杂)
我现在要强调的是,我正在寻找一种不依赖于第三方应用程序(例如memcached)的解决方案,因为这些应用程序被安装在各种不同的情况下,其中大多数情况下没有安装权限(例如:一个便宜的共享托管帐户)。
那么现在回到我正在做的事情上来,持久化到文件是安全的吗?在生产服务器安全性方面的第一个准则始终是禁用文件写入,但如果PHP不能写入,则我确实看不到任何方法可以进行缓存。有什么技巧/提示来提高安全性吗? 我是否遗漏了其他的持久化文件方法? 在“有限”的环境中,有没有更好的缓存方法?
8个回答

18

序列化非常安全且常用。但有另一种选择,即将数据缓存在内存中。可以查看memcachedAPC,它们都是免费且性能很高的工具。这篇关于PHP不同缓存技术的文章可能也会引起您的兴趣。


我希望我能保证访问memcached,但由于这些项目的性质,我无法控制部署...而且我真的不能将其设置为要求。知道允许PHP编写并不是世界末日是件好事。 - Oli
我会争辩(并在 https://dev59.com/T3VC5IYBdhLWcg3w-mZO 中已经这么做了),那里有非常安全的部分。序列化和写入本身并没有什么根本上的不安全之处,但在共享托管环境中这样做绝对不是理想情况。 - Alana Storm
3
Memcache和APC并不相似。它们唯一共同之处在于它们都使用RAM。Memcache用于缓存数据,而APC用于优化和缓存opcode。APC能够使几乎所有的PHP应用程序运行更快,但对于缓存对象和减少数据库查询方面则无济于事。 - Shane H
11
APC 不仅仅是一个字节码缓存,它还具有类似于内存缓存的缓存到内存的功能,类似于 memcache。 - Eran Galperin
3
为了适应不同的部署场景,最好编写一个标准的缓存接口,可以使用不同的缓存提供程序(如APC、Memcached、基于文件的缓存)实现。这样,每个部署就只需要进行配置即可。如果没有可用的内存缓存,则可以回退到基于文件的缓存。 - Tim

7

关于是否有其他持久化到文件的方法,我是否忘记了?

这种方法的效用有限,但如果您有一个非常强大的数据库查询,您可以将序列化对象写回到索引数据库表中。虽然仍需要进行数据库查询开销,但它只是一个简单的选择,而不是复杂的查询。

关于持久化到文件是否安全以及廉价共享托管账户

可悲的事实是,廉价的共享托管并不安全。您有多少信任度可以给那100、500或1000个其他人访问您的服务器?由于历史和(具有讽刺意味的)安全原因,共享托管环境下运行PHP/Apache作为非特权用户(其中PHP作为Apache模块运行)。安全性的理论是,如果面向世界的Apache进程被攻击,攻击者只能访问无法干扰重要系统文件的非特权帐户。

但不好的一面是,这意味着每当您使用PHP写入文件时,该文件的所有者都是相同的非特权Apache用户。对于系统上的每个用户都是如此,这意味着任何人都可以读取和写入这些文件。上述情况中的理论黑客也将访问这些文件。

PHP中还存在一种持久的不良实践,即将目录权限设置为777,以使非特权Apache用户能够写出文件,然后保留该目录或文件的状态。这使得系统上的任何人都可以读取/写入。

最后,您可能认为模糊不清可以保护您。"他们无法知道我的秘密缓存文件在哪里",但您错了。共享托管将用户设置为同一组,并且大多数默认文件掩码会使您的组用户对您创建的文件具有读取权限。有时候可以通过SSH登录到共享托管账户并导航到上级目录,就可以开始浏览系统上其他用户的文件。这可用于嗅探可写文件。

解决方案不太美观。某些主机将提供CGI Wrapper,让您将PHP作为CGI运行。这里的好处是PHP将作为脚本所有者运行,这意味着它将作为您而不是非特权用户运行。问题解决了!新问题!传统的CGI在二月份像糖浆一样慢。

有FastCGI,但FastCGI很棘手,需要不断调整。很少有共享主机提供它。如果找到一个提供它的主机,那么他们很可能已经启用了APC,并且甚至可以提供memcached的机制。


FastCGI并不是非常慢 - 比mod_php慢但更好。不过还是谢谢你的解释。+1 - Oli
没错,但在廉价的共享主机中很难找到。 - Alana Storm

4

我曾遇到相似的问题,因此编写了一个解决方案,即用PHP编写的内存缓存。它只需要PHP编译支持sockets即可。除此之外,它是一个纯PHP解决方案,并且应该可以在共享主机上运行得很好。

http://code.google.com/p/php-object-cache/


3

如果我需要写作,我会确保不在任何有PHP代码的地方进行编写。通常我的目录结构看起来像这样(在不同的项目中可能会有所变化,但是这是一个大概的想法):

project/
  app/
  html/
    index.php
    data/
  cache/

app不可被Web服务器写入(最好的情况是index.php也不能被写入)。cache可被写入,用于缓存解析模板和对象等内容。根据需要,data可能可被写入。即,如果用户上传数据,则会放入data文件夹。

Web服务器指向project/html,使用方便的方法设置index.php作为项目中每个页面运行的脚本。您可以在Apache中使用mod_rewrite或内容协商(我的首选,但通常不可能),或者任何其他您喜欢的方法。

所有真正的代码都位于app中,该文件夹无法直接被Web服务器访问,但应将其添加到PHP路径中。

这对我来说已经非常有效地运作了几个项目。我甚至能够让维基百科使用修改后的此结构版本。

哦...我会使用serialize()/unserialize()来进行缓存,尽管生成PHP代码具有某种吸引力。我所知道的所有模板引擎都会生成要执行的PHP代码,使得后期解析非常快。


1

你没有明确说明你为什么要缓存对象。你是想加快缓慢的数据库查询,避免昂贵的对象实例化,避免重复生成复杂页面,维护应用程序状态,还是只是强迫症地储存对象以备不时之需?

鉴于大多数低成本共享托管的恶劣限制,最佳解决方案将取决于您要实现什么目标。选择最便宜的共享托管意味着您必须接受与最好的工具不一起使用的事实。虽然很难量化,但在托管成本、网站性能和开发人员时间(即:快速、便宜或易用性)之间存在权衡。


1
如果您可以访问数据库查询缓存(例如MySQL),则可以序列化对象并将其存储在数据库中。数据库将负责将查询结果保存在内存中,因此速度应该非常快。

0

理论上可以在会话中存储对象。这可能会让你克服文件写入禁用的问题。此外,您可以将会话存储在mysql内存支持的表中,以加快查询速度。


这是一个好主意,但不够大。想象一下,1000个用户登陆网站并请求相同的数据五次。通常情况下,这将产生5000个数据库输入/输出操作。而使用您的方法,只需要进行1000次操作(但会有很多重复数据!)。而使用ASPNET的缓存(以及我上面提到的方法),只需要进行1次操作。这就是我所追求的。 - Oli

0
一些托管服务商可能已经编译了APC,这将允许您将对象存储在内存中。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接