Ruby on Rails 中文 Wiki
在Rails程序中整合php BB论坛 (changes)

显示修订历史自 #0 至 #1: 添加 | 移除

英语原文:http://wiki.rubyonrails.com/rails/pages/PhpBB+Integration

虽然 rForum 是个有前途的项目,但是至今还没有一个使用Ruby写的尽善尽美的论坛程序。所以,对于很多需要论坛模块的Rails项目来说,phpBb 多半是首选。本文讲述如何在Rails程序中整合phpBB2,以在你的网站中实现单一用户登录。实际的实现其实很简单。

整合 phpBB 和你的 Rails 程序

首先,我假设你的phpBB2和你的Rails程序运行在同一个数据库上。并且你采用”phpbb_”数据表名前缀。

在phpBB数据表结构中有两个最需要注意的表:@phpbb_users@ 和 phpbb_sessions

首先,创建一个用户的数据模型

rails script/generate model User

然后,在 app/model/user.rb 中加入以下语句

class User < ActiveRecord::Base
    set_primary_key "user_id" 
    set_table_name "phpbb_users" 

    def is_online? 
        tmp = User.find_by_sql( "SELECT session_user_id, session_logged_in FROM phpbb_sessions WHERE session_user_id=#{self.user_id}" )[0]
        if self.user_allow_viewonline == 1 && self.user_id != -1 && !tmp.nil? 
            return true
        else 
            return false
        end
    end
end

这样一来,我们告诉 Active Record? 我们的数据模式是在 phpbb_users 表基础上,并且使用 user_id 作为关键字段。 我们定义了方法 is_online? 是一个用于验证用户是否已经登录的数据库查询。(只有当用户登录,并且不隐身的时候,才返回 true。 在phpBB中 id == -1 意味是一个匿名用户)。

现在, phpBB 在你登录以后,在你的电脑上保存 cookie。所以可以使用 Rails 提供的 “cookies” 哈希来读取 phpBB的cookie。

这样的话,我们就可以识别当前登录的用户了

在 @app/controllers/application.rb@,写入:

class ApplicationController < ActionController::Base

    def get_user_by_sid( )
        sid = cookies["phpbb2mysql_sid"]
        return nil if sid.nil?
        User.find_by_sql( [ "SELECT phpbb_users.* FROM phpbb_sessions,phpbb_users WHERE session_id = ? AND phpbb_sessions.session_user_id = phpbb_users.user_id", sid ] )[0]
    end

end

这个方法通过读取 phpbb 的 session 数据 而返回一个 User 对象。 如果这个用户退出登录 phpBB,那么他也退出 Rails 程序。

从而在所有控制器和页面视图中,当你需要检查一个用户是否登录的时候,只需要执行 get_user_by_sid(), 如果返回结果非空,那么就是这个用户的数据 User 对象。

有了这些以后,你就可以在你的程序中创建任何同 phpbb 用户之间的关联。这个用户只需要登录一次,然后你就可以访问他们所有的phpbb中的属性(email, AIM, 头像 等等),和其他所有你的 Rails User 对象指定的数据。

自定义用户登录以后的去向

如果你希望用户登录 phpBb以后不是直接进入论坛,而是去你指定的页面,那么你可以以下的 php 脚本

<table border=0>
<tr><td colspan=2 align=left>
       <B>Please Login</b>
   </td>
</tr>
<tr>
   <td>
       Username:<form action="/forums/login.php" method="post" name="login_form" target=_top>
   </td>
   <td valign=top>
       <input type="text" name="username">
   </td>
</tr>
<tr>
   <td>Password:</td>
   <td>
       <input type="password" name="password">
   </td>
<tr>
   <td></td>
   <td align=center>
       <input type=hidden name="redirect" value=".."><input type="submit" value="Login" name="login"></form>
   </td>
</tr>
<tr>
   <td></td>
   <td align=center>
       <a href="http://www.yourdomain.com/forums/profile.php?mode=register" target=_top><span style="font-size: 0.8em">Register</span></a>
   </td>
</tr>
</table>

注意,以上脚本中的

<input type=hidden name="redirect" value="..">

中的值是你希望用户登录后访问的路径 (是相对你的论坛的路径)。

让用户在你的Rails程序中退出登录

如果你希望让用户直接在你的程序中退出登录,那么你可以使用以下代码

<form action="/forums/login.php?logout=true" method="post" name="login_form" target=_top>
  <input type=hidden name="redirect" value="..">(<a href="#" onClick="javascript:document.login_form.submit()">logout</a>
</form>

让用户在你的Rails程序中向 phpBB 论坛发贴

以下代码是我如何让用户在rails程序中向论坛发帖子。

首先,添加一些新数据模型:

# app/model/phpbb_forum.rb
class PhpbbForum < ActiveRecord::Base
    set_primary_key :forum_id
end

# app/model/phpbb_post.rb
class PhpbbPost< ActiveRecord::Base
    set_primary_key :post_id
end

# app/model/phpbb_posts_text.rb
class PhpbbPostsText < ActiveRecord::Base
    set_primary_key :posts_text_id
    set_table_name :phpbb_posts_text
end

# app/model/phpbb_topic.rb
class PhpbbTopic < ActiveRecord::Base
    set_primary_key :topic_id
    belongs_to :user, :foreign_key => 'topic_poster'
end

然后在你的程序中加入以下代码(我放在 app/controllers/application.rb 从而所有的控制器都可以使用)

def post_topic( forum_id, user_id, subject="test subject", content="test content" )
        forum = PhpbbForum.find( forum_id )
        return if( forum.nil? || user_id.nil?  || forum_id.nil? || subject.nil? || content.nil?  )
        return unless validate_admin_with_hidden_action()
        # Apply post
        # Update forums table with new posts count, new topic count, and forum_last_post_id
        forum.forum_posts += 1
        forum.forum_topics += 1
        # Update user post count
        user.user_posts += 1
        user.save
        # Update posts with new topic_id,
        topic = PhpbbTopic.create
        post = PhpbbPost.create
        post.topic_id = topic.id
        post.forum_id = forum.id
        post.poster_id = user.id
        post.post_time = Time.now.to_f.to_i
        post.poster_id = user_id
        post.save
        # Create new topic
        topic.forum_id = forum.id
        topic.topic_title = subject
        topic.topic_poster = user_id
        topic.topic_time = Time.now.to_f.to_i
        topic.topic_first_post_id = post.id
        topic.topic_last_post_id = post.id
        topic.save
        forum.forum_last_post_id = post.id
        forum.save
        # Create new posts text
        post_text = PhpbbPostsText.new
        post_text.post_id = post.id
        post_text.bbcode_uid = "3edc9030fc" 
        post_text.post_subject = subject
        post_text.post_text = content
        post_text.save
        return topic.id
    end
end

以上代码没有被测试过,仅用来表达实现的想法。它们应该被更好地封装到数据模型中去,并且被完整测试。

其他

还有一些可能有用的东西

首先,在数据模型中:

class PhpbbForum < ActiveRecord::Base
    set_primary_key :forum_id
    has_many :phpbb_topics, :foreign_key => 'forum_id'
end
class PhpbbPost< ActiveRecord::Base
    set_primary_key :post_id
    belongs_to :phpbb_topic, :foreign_key => 'topic_id'
    belongs_to :phpbb_forum, :foreign_key => 'forum_id'
    belongs_to :user, :foreign_key => 'poster_id'
    has_one :phpbb_posts_text, :foreign_key => 'post_id'

    def text
        self.phpbb_posts_text.text
    end
end

class PhpbbPostsText < ActiveRecord::Base
    set_primary_key :post_id
    set_table_name :phpbb_posts_text
    belongs_to :phpbb_posts, :foreign_key=>'post_id'

   def text
       self[:post_text]
   end
end

class PhpbbSession < ActiveRecord::Base
    set_primary_key :session_id
    belongs_to :user, :foreign_key => 'session_user_id'
end

class PhpbbTopic < ActiveRecord::Base
    set_primary_key :topic_id
    belongs_to :user, :foreign_key => 'topic_poster'
    has_many :phpbb_posts

    def last_post
        PhpbbPost.find( self.topic_last_post_id )
    end
end

然后有一个类似以下的用户数据模型

class User < ActiveRecord::Base
    set_primary_key "user_id" 
    set_table_name :phpbb_users

    has_many :phpbb_posts, :foreign_key => 'poster_id', :order=>'post_time DESC'
    has_one  :phpbb_session, :foreign_key=>'session_user_id'

    def is_online? 
        tmp = User.find_by_sql( "SELECT session_user_id, session_logged_in FROM phpbb_sessions WHERE session_user_id=#{self.user_id}" )[0]
        if self.user_allow_viewonline == 1 && self.user_id != -1 && !tmp.nil? 
            return true
        else 
            return false
        end
    end

    def sid
        return self.phpbb_session.nil? ? -1 : self.phpbb_session.session_id
    end

    # Grab latest post for this user
    def latest_post
        self.phpbb_posts.first
    end

end

现在你很方便的做:

Post.find( 1 ).text
Post.find( 1 ).user
Post.find( 1 ).topic
Post.find( 1 ).forum
User.find( 2 ).last_post.text

本条目被以下条目链接: