我们有一个旧的遗留PHP应用程序。现在我想用Ruby on Rails编写一个新的应用程序模块。
部署是一个问题。我想应该可以在一台Apache服务器上运行PHP应用程序(通过mod_php)和RoR应用程序(通过mod_proxy / mongrel)。我不想使用mod_rails,因为它需要通过fcgi运行php。破坏某些东西的风险也是如此。 PHP和RoR都将使用相同的数据库。
棘手的部分是如何将登录信息从PHP应用程序传递到RoR应用程序。用户登录PHP并将其信息存储在PHP会话数据中。 RoR应用程序将放置在主PHP应用程序的子目录中(例如www.example.com/railsapp)。因此RoR应该接收所有HTTP cookie。问题是如何从RoR应用程序中提取PHP会话数据。
上面这只是我的第一个想法,因为PHP mod和RoR之间可能存在竞争条件,因此相当糟糕。我可以修改PHP应用程序,以便在用户登录时在DB中存储一些信息。但我不知道如何处理PHP会话数据过期并且DB中的某些数据应该更新(注销用户)的情况。
有没有人解决过类似的问题?或者至少可以指出一个最有希望的方向?
更新:应该可以配置mod_php来存储sql DB中的会话数据。这样就不会有竞争条件。数据库引擎应该防止竞争条件。
Update2:实际上可以在prefork模式下使用带有Apache的mod_rails。这是mod_php所要求的。建议mod_rails以worker mpm模式运行Apache。因此,PHP / RoR应用程序的整个部署大大简化了。
答案 0 :(得分:2)
首先,如果您将rails应用程序放在子目录中,则可以使用mod_rails。在PHP站点的配置中,您可以拥有一个具有rails的根目录的位置。
<Location /railsapp>
DocumentRoot /.../app/public
</Location>
要将会话转到rails端,您可以在rails上创建一个连接页面并从PHP端调用它并传入一些数据进行登录。您只需要保护此页面免受来自localhost的任何请求(易于操作)。
您也可以切换rails以使用数据库来存储其会话,然后您应该能够生成会话ID,将其存储在具有正确名称和密码的cookie中,并使用该手动在数据库中创建会话标识。
您也可以(我推荐)在rails侧有代理页面,用于登录用户并将其重定向到所需的页面。你可以这样做(不是实际的工作代码,但你明白了):
PHP
$key = md5hash($user_id . $user_password_hash . $timestamp)
$url = "/railsapp/proxy?userid=" . $user_id . "&key=" . $key . "&page=home%2Fwelcome"
<a href="<$ $url $>">Rails App</a>
滑轨
map.proxy 'proxy', :controller => 'proxy', :action => 'connect'
class ProxyController < ActionController::Base
def connect
key = ...
if params[:key] == key
login_user params[:userid]
redirect_to params[:page]
else
render :nothing, :status => 403
end
end
end
答案 1 :(得分:2)
之前我已经完成了一个混合的PHP / RoR应用程序(旧的PHP代码,新的hawt RoR功能,因为需要修复它的东西重新实现)。它并不是那么难 - 您只需将PHP作为普通文件提供,并使用404处理程序将其他所有内容重定向到Rails应用程序。
就会话数据而言,可以将其填充到数据库中,但如果您愿意编写/查找例程来读取和编写PHP的编组数据格式,那么PHP使用{{ 1}}确保在读/写会话数据文件时没有竞争条件。在Rails应用程序中执行相同的操作以获得最小的痛苦。
答案 2 :(得分:1)
首先,您似乎通过混合使用这两种技术来解决问题。我的第一个建议是“不要那样做”。
但是,由于你可能不会听取这个建议,我会就你的实际问题提出建议。在我看过的数据库中存储会话数据的PHP应用程序中,我注意到了清理数据的方法。两者都包括始终为记录添加时间戳,以便您知道它们的年龄,并在用户处于活动状态时不时刷新时间戳(有时每个页面视图,有时不太常见,取决于预期的负载和查询计数)。
如果您的应用程序执行相对较少的数据库调用,因此有一点闲暇时间,您可以针对每个页面视图对至少某些页面的会话表运行额外查询。这意味着额外的查询和繁忙的应用程序是一个问题。替代方案往往是一个定期运行以清理过期记录表的cron作业。这些定期清理作业也可以仅在特定的其他任务完成时运行(例如用户登录,因为您必须设置会话数据,这通常有点慢)。
答案 3 :(得分:0)
嘿,我一直认为这实际上是一个非常普遍的问题,那些从php迁移到ruby的人在php中拥有legacey应用程序/数据,我很惊讶它没有被问到更多。
我很想接受以下两种方法中的任何一种,这两种方法在过去都运作良好。第二个选项需要更多的工作,它们都需要修改现有的登录代码:
1)使用openid处理您的登录信息,这样您就不必担心自己的解决方案了。运行您自己的openid服务器或使用谷歌,雅虎等。将您的每个应用程序作为一个独特的子域运行。有rails和php的openid插件/代码,它是一个久经考验的安全标准
2)使用memcached存储登录会话(而不是数据库)。有一个登录页面(在你的php app或rails app中)。无论你是访问ruby应用程序还是php应用程序,都会与此类似。
a)用户尝试访问登录受保护的页面
b)应用程序检查自己的会话数据以查看用户是否已登录
c)如果存在正确的会话数据,则用户登录并继续应用
d)如果App无法找到浏览器cookie的当前登录会话检查
e)然后App检查memcache是否有这个cookie密钥。
f)如果cookie密钥存在,那么用户必须登录(否则重定向到登录页面)
g)app从memcached中获取user_id(存储为cookie密钥),以便它知道哪个用户已登录
h)app设置登录会话,因此除非会话过期,否则不必再次超过c
这是正在发生的事情的过度简化版本,但确实有效。 我会在这种情况下使用memcached,因为它有你自己定义的值的自动过期,并且很快。请记住,不要在应用程序甚至用户标识之间传递用户名和密码。传递一个唯一键,它只是指向存储在DB / memcached中的信息的指针
答案 4 :(得分:0)
1)我在开发机器和服务器上的单个prefork Apache上同时成功使用Passenger和mod_php。
2)我将通过HTTP质询/响应序列或可能通过共享的memcached密钥连接应用程序。