Support for more than one domain
| Project: | reCAPTCHA |
| Version: | 5.x-2.x-dev |
| Component: | reCAPTCHA Captcha |
| Category: | feature request |
| Priority: | critical |
| Assigned: | Unassigned |
| Status: | active |
Jump to:
I've just had a look at both recaptcha and your Drupal module and I like it quite much. There's one point, though, why I can't really use it at the moment:
I'm using one Drupal installation but have 2 domains (.de,.eu) pointing to it. I've got recaptcha keys for both domains but can, of course, only enter the keys for one of them in the recaptcha settings. So, visitors on the other domain will either get no CAPTCHA image at all or their input cannot be validated by the server due to the wrong keys.
I'm not sure whether this feature request is even reasonable ;) But would it be possible to get more than one set of keys stored? I know that it's possible via PHP to query which of the domains is currently visited...

#1
Interesting, right now it uses Drupal's variable_get() to retrieve the keys. But if you're using multiple domains under the same Drupal database, with the same content, this solution will not work, since it will just load the one set of keys. If you think of any solution around it, I'd be most interested in hearing about it.
#2
Well, yes... one database but multiple domains. At least for the time being.
I'm relatively new to Drupal (less than half a year, so not really competent in this area) but learning a lot and definitely not unwilling to help out here :)
I have an idea or two, though. Just had a look at the variables table. Perhaps, instead of storing strings for the keys, an array could be stored there. Something like this:
$recaptcha_keys = array('example.com_public_key' => '...',
'example.com_private_key' => '...',
'example.org_public_key' => '...',
'example.org_private_key' => '...',
...
);
Or, when not using an array, the current variable names could be prefixed/suffixed by the domain name. For the "normal" user nothing needs to change or perhaps "default" could be used as the domain name? By querying
$_SERVER['HTTP_SERVER']it would be clear which keys to actually retrieve.How to realise the key input in a form, though, I have no clue right now.
Would you think it's worth doing? Feasible?
Kind regards,
Marco
#3
After doing some brainstorming, I now know how to support multiple domains, under one databsae, with different reCAPTHCA keys. I'll start work on it once I get the time. Shouldn't take that long.
#4
That's just great news and highly appreciated. Thank you very much!
#5
I have some good news, and I have some bad news:
Good news: Got it working
Bad news: If your domain is too large, it breaks the system.
How the solution works: Instead of just storing the private and public keys in the variables tables in the database, it puts $base_url in there as well.
recaptcha_private_key becomes 'recaptcha_' . $base_url . '_private'.
recaptcha_public_key becomes 'recaptcha_' . $base_url . '_public'.
Although it does work, it breaks the system if your base url is large, because the name field in the variable table is restricted to 48 characters. A way around this is to facilitate the creation and deletion of an entirely new table in the database. Does this really warrant the creation of a new table though?
We could also make the name smaller.... 'recaptcha_' . $base_url . '_prv' and '_pub', maybe? Then that would let us have the $base_url be 34 characters long.... Might help.
#6
Do you think we'd have to split this up into a new database table? Or just use the variable_get/set solution?
#7
Sorry, been away for a few days...
For me personally, the set/get would completely suffice. But of course, I can't speak for other users here. So maybe the best/easiest solution for now would be to use that and wait for feedback from others? I'm not even sure how many other users would even need this feature...
Kind regards,
Marco
#8
drumlin, I think you can apply your idea by placing code like this in the settings.php files for each domain.
$conf = array('repactcha_public_key' => '...',
'repactcha_private_key' => '...',
);
#9
No, unfortunately not. Both domains point to the same Drupal installation (and same database and so on) and therefore use the same settings.php as well...
#10
Does it work if you separate the settings.php files?
sites/mysite1.com/settings.php:
// Database settings here
// ....
$conf = array(
'recaptcha_public_key' => 'my key for site #1',
'recaptcha_private_key' => 'my key for site #1',
);
sites/mysite2.com/settings.php:
// Database settings here - Same as mysite1.com's
// ....
$conf = array(
'recaptcha_public_key' => 'my key for site #2',
'recaptcha_private_key' => 'my key for site #2',
);
#11
I just tried it, and it does work. Thanks a lot for the tip, drumlin.
#12
Sending some thanks my way is okay with me. I mispelled recaptcha so maybe I got an automatic disqualification. :(
#13
Haha, thanks christefano. Now is this a feature that should be put right into the reCAPTCHA module's UI itself?
#14
I can go either way myself, but when I think about new admins who are starting out my vote is definitely for a UI. New admins might have a problem editing their settings.php file ... but then again a new admin will learn things pretty fast by running a multisite setup. I'm not 100% sure, but I'm leaning towards a UI (as long as you have time and willingness to code it).
Let's make it easier for everyone rather than a trial by fire. Until then, the settings.php method should probably be in the docs.
#15
Yeah, that should do for now.
#16
If anyone has any good ideas on how this would be implemented from the user administration stand point, please be my guest. Right now, I think modifying settings.php is the best solution.
#17
#18
Just run into the same issue myself. We are running various domains all pointing to the same virtual host / drupal configuration - so storing the captcha keys in the settings file like you proposed above is not yet an option. I see three ways of fixing it:
1. Not so pretty
Keep the HTML admin frontend and introduce a notation which will allow to enter multiple domains->key mappings. For instance:
Private Key Text-Area
-------------------------------
|".*\.example.com" : "[KEY]" |
|".*\.example.cnet" : "[KEY]" |
-------------------------------
Public Key Text-Area
-------------------------------
|".*\.example.com" : "[KEY]" |
|".*\.example.cnet" : "[KEY]" |
-------------------------------
Assumptions:
Options:
(substr_compare ($_SERVER['SERVER_NAME'], $myDomainName,-1 , strlen($myDomainName),true) == 0)2. Slightly better
Use an multidimensional associative array in settings.php:
$recaptcha_keys = array(
".*\\.example\\.com" => array
(
"private" => "[KEY]",
"public" => "[KEY]",
),
".*\\.example\\.com" => array
(
"private" => "[KEY]",
"public" => "[KEY]",
)
)
Options
@see 1, not using regular expressions to make things easier
3. As it should be
Well, at least as it appears to me, the best solution would be to introduce a new preferences table / schema in the database and store the mapping over there.
This would require some CRUD Administration Frontend hacking so one could add as many domains and keys as needed. I'm not familiar with the UI-Preferences and Schema API of Drupal yet, so I have no idea how difficult this might get to implement this.
I could provide you with patches or SVN commits for solution 1 or 2 until monday next week. Not sure about the 3rd one.
Cheers!
Paul.
#19
What about using keys_api? It works great for the Gmap module Google keys. I'm hoping to see this functionality for recaptcha and keysapi and then all supported by the domain module, so that we really can forget about all the hassles with keys.
#20
To be honest? I did not even know there is such a thing. After glancing quickly over the sourcecode it might be the way to go, at least for a intermediate solution. The keys_api seems to be still beta which usually bounces me of of using a module for a production environment. On the other hand the source looks simple enough not to expect any bad surprises.
My point is: I need this kind of functionality ASAP. Being a developer myself, i have no problem with getting my hands dirty and do it by myself - but I would rather like to make the changes in a way where not only I but also the official module release could benefit from this. Therefore I would like to see one of the module maintainers giving me a comment which solution they would like to see, if they want me to implement this, or would like to do it by themselves.
Thanks for the hint!
#21
I'm in a similar position - I need this functionality asap as I'm hoping to rollout the domain module and recaptcha isn't aware of multiple domains. I'm in comms with agentrickard (the developer of domain and an incredibly capable developer) on this particular issue so I'll send him a chaser and see where we're at. He didn't think it was much work and I was even prepared to use some of our charity funds to fix it! If anyone else would like to chip in for development costs we'd be very grateful.
Cheers, Stephen
#22
In the domain access world, just use Domain Configuration (supplied module) and add an implementation of hook_domainconf() to the recaptcha module.
http://therickards.com/api/function/hook_domainconf/Domain
Domain Configuration works -- similar to this thread -- by inserting a dynamic variable lookup function into settings.php.
See http://therickards.com/api/file/domain_conf/settings_domain_conf.inc/Domain
You could do something similar for ReCaptcha with a small database table, storing the domain_id or a lookup string, and key value.
Remember that settings.php is a PHP file, so it can contain run-time code.
#23
We've done this in the past, using settings.php:
<?phpswitch ($_SERVER['HTTP_HOST']) {
case 'example.com':
$conf['recaptcha_public_key'] = '6LdvOQEAAAAAAKlYCkMolKm3vbDBYYiR7UKcKuF2';
$conf['recaptcha_private_key'] = '6LdvOQEAAAAAADNDHPeOOsIeF7bD1SIbbmmKOUWS';
break;
case 'myotherexample.com':
$conf['recaptcha_public_key'] = '6LdvOQEAAAAAAKlYCkMolKm3vbDBYYiR7UKcKuF3';
$conf['recaptcha_private_key'] = '6LdvOQEAAAAAADNDHPeOOsIeF7bD1SIbbmmKOUWT';
break;
}
?>
Moving this stuff to a user interface would be nice though. Although I'd rather not make reCAPTCHA depend on another module, it would be nice to have the ability to use its functionality if it exists. For example, we could have it use what's there now, and then provide more advanced configuration of the domain keys if Keys API is there.
#24
@Rob
So I presume you are more into the solution 3 I proposed? I'm pretty neutral about this. I could either use the settings.php like you did, or get into Drupal development and figure out how get it done right. What about the "not so pretty solution"? This would not require any DB schemas to be created or any usage of 3rd party modules. After adding some help text and form validation to it it might be be even not that terrible in terms of usability.
Mixing the Keys API and the "native" preferences storage might get a bit tricky though. As far I understand keys api provides its very own administration frontend which we would either need to copy or give the user a hint that he cannot use the native preferences panel anymore if he decides to go multidomain with keys_api. Or just maybe I am missing some fundamental concept of hooks and api reusage here.
#25
I'd urge you to install the keys_api and gmap modules on a site and have a look at how it works. Surprisingly simple and effective. On the Gmap config screen, where it normally shows a text field to enter the key, the text field is replaced by the text link "Managed by keys api".
The keys_api is clearly designed for any module to use the hooks it provides.
As for the concern about making "reCAPTCHA depend on another module" - it would only be dependent on keys_api if keys_api was installed - just as GMap can live with it or without it.
IMHO keys_api is one of those very simple and highly useful modules that should be in core.
#26
btw the recommended solution by Rob Loach on March 19, 2008 @ 14:14 works fine with the domain module.
#27
Re: #22
Just a clarification: I am not suggesting that you use Domain Access to handle this. But if you want to support multiple keys inside of DA, there is already a mechanism for that, similar to implementing pathauto or views hooks in your module.
#28
The Domain Access module is also quite large, and I see it taking a while to port to Drupal 6.
I have had a quick look through the Keys API code, and it seems that they make a query to the database every time a key is required. It would be better if they used the variable table, because it's already cached and doesn't require a hit to the database..... I'll submit an issue.
#29
DA is only large because it is a suite of modules -- so the tarball looks large. Working on the port to 6 now.
Domain Configuration, which is relevant here, adds one lookup query -- it basically stores a variable cache per site configuration in order to add $conf overrides in a dynamic fashion. Think of it as option #23 with a UI for managing multiple $conf overrides.
As I say over in the DA issue queue, the solution in #23 is perfectly fine. But if you are using Domain Configuration anyway, then you should use the provided hook, since adding the new code to settings.php duplicates features that already exist.
If all you need to store are the keys, here's the code:
<?phpfunction recaptcha_domainconf($domain) {
$form['recaptcha'] = array(
'#type' => 'fieldset',
'#title' => t('Recaptcha'),
'#collapsible' => TRUE,
'#collapsed' => FALSE,
);
$form['recaptcha']['recaptcha_public_key'] = array(
'#type' => 'textfield',
'#title' => t('Public key'),
'#default_value' => variable_get('recaptcha_public_key', ''),
'#size' => 30,
'#maxlength' => 40,
'#description' => t('The public key given to you when you <a href="@url" target="_blank">registered at reCAPTCHA.net</a>.', array('@url' => url(recaptcha_get_signup_url($_SERVER['SERVER_NAME'], variable_get('site_name', ''))))),
);
$form['recaptcha']['recaptcha_private_key'] = array(
'#type' => 'textfield',
'#title' => t('Private key'),
'#default_value' => variable_get('recaptcha_private_key', ''),
'#size' => 30,
'#maxlength' => 40,
'#description' => t('The private key given to you when you <a href="@url" target="_blank">registered at reCAPTCHA.net</a>.', array('@url' => url(recaptcha_get_signup_url($_SERVER['SERVER_NAME'], variable_get('site_name', ''))))),
);
return $form;
}
?>
Note that we do not set these fields to "Required' in case the sites wish to share the master site key.
Of course, if you are not using DA, none of this matters.
If would be nice to see the hook implemented here, though.
#30
Other modules can still contain their own GUI for setting an API key through Keys API using the following function:
<?php/**
* This function developers can use to allow submission of a key on their own settings page.
*
* @param $service
* The name of the service you want to get the key for.
* @param $domain
* The domain you want to get the key for. Use $_SERVER['HTTP_HOST'] for current domain.
* @param $key
* The API Key.
*/
function keys_api_set_key($service, $domain, $key) {
db_query("DELETE FROM {keys_manage} WHERE domain_name = '%s' AND service = '%s'", $domain, $service);
db_query("INSERT INTO {keys_manage} (domain_name,service,api_key) VALUES('%s','%s','%s')", $domain, $service, $key);
}
?>
This allows modules to still allow an API key to be set without leaving their settings page while allowing the Keys API's page to still be able to manage all the keys.
#31
@Rob #28
Originally I had used variables to store the keys (as the README.txt file still makes reference to, I need to change that), but opted not to for some reason. I think it was that I thought it would be better to make a simple database call to get the key vs. storing however many keys as variables when a site only needs the one(s) for it's domain. I don't know performance wise which would be better, but will be willing to make the appropriate changes to use variables instead if need be.
#32
So is this problem already solved in the new version? Or not...
#33
Nevermind, didn't read the full thread...
See also: Keys Feature Request for reCAPTCHA support