处理用户自定义域的最优雅方法是什么?

时间:2012-01-20 19:53:21

标签: cakephp cakephp-2.0

在我的网站上,用户可以通过http://mysite.com/vanity_url访问公开个人资料。我想允许用户将自己的域指向我网站上的个人资料页面。 Just like Bandcamp does

我的Profile模型有以下两个字段来处理:vanity_url,这是普通的用户名字段类型;以及一个新的custom_domain,这是他们自己的域名,例如example.com

这是我到目前为止所做的,但我担心它可能不是最优雅,最安全,最有效的方式。

首先,我确保Apache的DocumentRoot设置为我应用的webroot目录,因此我可以告诉用户将他们的DNS指向我网站的IP。

现在,我的routes.php上的路由规则就是这样的:

if (preg_match('/mysite\.com\.?$/', $_SERVER['SERVER_NAME'])){
    // Normal routes when visitors go to my domain
    Router::connect('/', array('controller' => 'pages', 'action' => 'display', 'home'));
    Router::connect('/pages/**', array('controller' => 'pages', 'action' => 'display'));

    // Move all other actions to a separate '/app/' area
    Router::connect('/app/:controller/:action/**');
    Router::connect('/app/:controller/**');

    // Handle profile URLs
    Router::connect('/:profile/**', 
        array('controller' => 'profiles', 'action' => 'view'), 
        array('pass' => array('profile'), 'profile' => '[0-9a-zA-Z\-\_]+')
    );
}
else{
    // If visitors come via a URL different to mysite.com, I let 
    // the ProfilesController deal with it passing the current SERVER_NAME 
    // as a param to the 'view' action
    Router::connect('/', array(
        'controller' => 'profiles', 
        'action' => 'view', 
        $_SERVER['SERVER_NAME'], // 'url' param
        true // 'customDomain' param
    ));
    Router::redirect('/*', 'http://mysite.com');
}

这就是view上的ProfilesController操作的样子:

public function view($url = null, $customDomain = false) {
    if ($url){
        // Find the profile by its vanity_url or its custom_domain
        $findOptions = array(
            'conditions' => $customDomain? 
                array('custom_domain' => $url) : 
                array('vanity_url' => $url) 
        );
        if ($profile = $this->Profile->find('first', $findOptions)) {
            $this->set('profile', $profile);
        }
    }
    else throw new NotFoundException(__('Invalid profile'));
}

这种方法可能会遇到什么问题?

此外,有没有人知道为什么Bandcamp会要求用户创建 CNAME 而不是 A 记录来设置子域名?我错过了我应该考虑的事情吗?

编辑有人帮我弄清楚最后一点:似乎你不能轻易使用CNAME记录将裸域指向另一个。主要问题仍然是开放的。

2 个答案:

答案 0 :(得分:1)

我在一年前使用蛋糕1.3做了类似的事情

此解决方案有4个主要步骤:

  1. 拥有一个域模型和域数据表,用于记录所有可能的自定义域和视图,供用户输入其自定义域
  2. 在AppController中的beforeFilter中创建域检查代码,并将用户数据保存到会话
  3. 负责查看公共个人资料的Controller操作需要引用保存到会话的相同用户数据
  4. 您的用户需要使用其域名注册商正确设置CNAME和A记录
  5. 步骤1域模型和数据表

    我做的是我有一个名为域

    的表

    每个域都包含我认为只是http:// ....

    的网址

    域名属于用户

    用户拥有多个域名

    domains
    ==========
    id    web_address    user_id    main
    

    main是一个tinyint,表示这是否是因为User hasMany Domain而使用的主要URL。

    所以会发生什么是用户需要为Domain创建一个或多个新记录。

    步骤2 AppController的beforeFilter中的代码,以确定要显示的公开个人资料 接下来,您的代码需要能够根据每个http请求提交的URL检索用户ID。

    此时用户指的是查看其公开个人资料的用户。如果你有一个,请不要将它与loggedIn用户混淆。

    我建议您在之前的AppController过滤器中执行此操作。

    像这样的东西

      $currentUser = $this->User->getByDomain(FULL_BASE_URL);
      $this->Session->write('CurrentUser', $currentUser);
    

    用户模型的getByDomain代码也是一项练习。鉴于我已经解释了域的架构

    ,应该很容易

    在编写currentUser之前,您可能需要检查Session数据中的currentUser,因为您不希望一直写会话数据,尤其是当访问者一次又一次访问同一网页时。

    您可能需要将上面的代码段更改为以下内容:

      $currentUser = $this->Session->read('CurrentUser');
    
      if(empty($currentUser) OR (!$this->checkUrlAgainstDomain(FULL_BASE_URL, $currentUser['Domain']['domain']))) {
            $currentUser = $this->User->getByDomain(FULL_BASE_URL);
                        $this->Session->write('CurrentUser', $currentUser);
        }
    

    函数checkUrlAgainstDomain再次为你练习。

    步骤3 AppController的beforeFilter中的代码,以确定要显示的公开个人资料 您将使用会话中保存的CurrentUser数据来确定要显示的用户的公共页面。

    我将此作为练习留给您在行动视图下的UsersController中找出

    第4步,您的用户需要在其域名注册商中输入以下内容 然后,您的用户需要访问他们的域名注册商,并在您链接到的常见问题解答中执行与BandCamp用户类似的操作。

    • 用户的“www”子域名应使用CNAME指向example.Lucho.com

    • 用户的根域(没有www)应该有一个指向服务器IP地址的A记录,即Lucho.com所在的位置

    • 用户必须同时添加这两个域管理页面,如前面所述。域名最多可能需要48小时才能完全更新。

答案 1 :(得分:1)

我想没有更好的方法:P