PDA

Pogčedajte punu verziju : Subdomain iz $_SERVER['HTTP_HOST']


User
18. 03. 2010., 15:26
Aplikacija prikazuje sadržaj na osnovu domena na kome se servira (uključujući i poddomen). Jedni podaci se prikazuju za www.domain.com, drugi za dev.domain.com, treći za test.domain.com i tako dalje.

Pokušavam da rešim sledeći problem: automatski izvršiti redirekciju na www poddomen ukoliko korisnik dođe na domen bez ikakvog poddomena. Na praktičnom primeru:
1) korisnik je došao na example.com => izvrsiti redirekciju na www.example.com
2) korisnik je došao na test.еxample.com (ili www.example.com ili dev.example.com) => ne menjati ništa

Trenutno radim preg_match nad $_SERVER['HTTP_HOST']:
preg_match ("%^(?:([A-Za-z0-9\-_]+)\.)?([^/.]+)\.([^/:]+)(\:[0-9]+)?%i", $_SERVER['HTTP_HOST'], $data);

To radi dobro sa TLD koji nemaju second level, jer odmah saznam da mi je $data[1] prazan, prependujem www i izvrsim redirekciju bez upita u bazu.

Problem nastaje sa raznim ccTLD i second level TLD, kao sto su .co.uk ili .com.br - tada sam primoran da vršim upite u bazu što želim da izbegnem.

Uzmimo za primer da korisnik dolazi na example.co.uk, a da se aplikacija servira sa www.example.co.uk. Trenutni regex ce vratiti:
$data[1] = 'example';
$data[2] = 'co';
$data[3] = 'uk';

Tj dobiću da je pronađen subdomain 'example'. Potom vršim upit u bazu po domenu 'example.co.uk'. Ukoliko ne dobijem rezultat, pokušavam sa 'www.example.co.uk'. Tim upitom nalazim domen i vršim redirekciju.

U slučaju da ni 'www.example.co.uk' domen nije nađen u bazi, izvrsiću redirekciju na neki treći domen, ali to je trenutno manje bitno.

Ima li neko bolju ideju kako bolje razrešiti ovaj problem?

JovanT
18. 03. 2010., 16:03
Мислим да нема потреба да се компликује оволико. Твоје потребе би могао да задовољи и обичан explode('.', $_SERVER['HTTP_HOST']);. Тиме ћеш добити све појединачне делове домена. Затим можеш да провераваш предзадњи део. Уколико је он нешто из опсега (co, its, in...), знаш да се ради о .ccTLD па сходно томе вршиш даље провере.

Ако ово није довољно поуздано, онда можеш да идеш обрнутом логиком - провераваш да ли се ради о интернационалном домену (com, net, org, info, eu, asia...). Ако јесте, третираш га на један начин, ако није - на други. Верујем да се све ово можеш решити уз неколико if-ова.

noviKorisnik
18. 03. 2010., 16:14
To radi na nivou .htaccess, ne u PHP. Recimo ovako (brzi primer, hvala Google...
Options +FollowSymlinks
RewriteEngine on
rewritecond %{http_host} ^domain.com [nc]
rewriterule ^(.*)$ http://www.domain.com/$1 [r=301,nc]

User
18. 03. 2010., 16:41
To nije resenje. Evo vise primera:

www.domain.com ne menjati
primer.domain.com ne menjati
drugi.domain.com ne menjati
domain.com se menja u www.domain.com

www.domain232.com.br ne menjati
primer.domain32423.com.br ne menjati
example2323.com.br se menja u www.example2323.com.br

Nije mi bilo u planu da za svaki domen koji se kreira pravim novu liniju u .htaccess fajlu.

Ja ne znam na kom ce (pod)domenu korisnici pokretati applikaciju. Oni najcesce imaju *.domain.com => domain.com alias. Aplikacija se servira sa jednog (ili vise) njihovih poddomena (ne domena bez poddomena) - to je obicno www.domain123.com ali moze da bude bilosta.domain123.com (kao i bilo koji drugi TLD).

sinisabobic
18. 03. 2010., 16:48
Imao sam slican problem (sa jedinom razlikom da su mi trebali domainovi kod kojih se znalo da je SDL veci od 3). Problem je resen na sledeci nacin:

explode-ujes po "."

onda proveravam po broju clanova u dobijenom nizu

ukoliko je 2 to je domain formata example.com
ukoliko je 3 onda se proverava srednji clan, pa ako je on manji ili jednak 3 onda je to formata example.co.uk npr a ako nije onda je to formata nesto.example.com

a sve ostalo je formata nesto.example.co.uk

(ne znam koji su detalji, ali ovo je meni resavalo sve sto mi je trebalo za tu situaciju)

sinisabobic
18. 03. 2010., 16:54
Ako je .htaccess u igri probaj nesto ovako

RewriteCond %{HTTP_HOST} !^(.*)\.([^\.]+)\.com$ [NC]
RewriteCond %{HTTP_HOST} ([^\.]+).com$ [NC]
RewriteRule ^(.*)$ http://www.%1.com/$1 [L,R=301]


pa ako ti to radi za sve com domainove smislicemo nesto i za ostale :)

UPDATE: ja koristim ovo za neke sajtove gde imam po 300+ domainova koji teraju isti kod

bOkIcA
18. 03. 2010., 17:39
Ako sam dobro skapirao radi se o aplikaciji koja "tera" vise domena.
U tom slucaju bih generisao (array) listu domena pri svakoj promeni u bazi, dalje bi se prema tome radila provera i redirekcija.

bOkIcA
18. 03. 2010., 19:28
mikro vreme odvojih...
Mislim da bi ovako nesto radilo dovoljno brzo cak i na vecem broju domena.

$current_domain = "example.co.uk"; //$_SERVER['HTTP_HOST']

$domains = array('example.com',
'example.co.uk',
'nekidomen.com',
'nekinas.iz.rs',
'test.co.rs');

foreach($domains as $key=>$domain) {
$strpos = strpos($current_domain, $domain);
if ($strpos > 0 AND preg_match("/\.$domain$/", $current_domain)) {
$success = TRUE;
break;
} elseif ($strpos === 0 AND preg_match("/$domain$/", $current_domain)) {
// redirection here...
exit("redirecting to www.{$domains[$key]}");
}
}

if (!isset($success)) {
exit('domain not exist');
}

echo "show content w/o redirection";

bluesman
18. 03. 2010., 19:49
Biće bar 2000+ domena i broj raste vremenom ... već sada ih ima oko 300 a još nismo ni počeli.

bOkIcA
18. 03. 2010., 19:52
Na 50.000 domena u array-u vreme prolaska kroz petlju je na mom racunaru 0.035 sec.
A verujem da sigurno moze jos da se optimizuje.

bOkIcA
18. 03. 2010., 19:59
Dodavanje jednog IF-a i vreme prolaska kroz petnju (na tih 50.000 stavki u array-u) je sada ~ 0.027 sec.

foreach($domains as $key=>$domain) {
if ($strpos = strpos($current_domain, $domain) !== FALSE) {
if ($strpos > 0 AND preg_match("/\.$domain$/", $current_domain)) {
$success = TRUE;
break;
} elseif ($strpos === 0 AND preg_match("/$domain$/", $current_domain)) {
// redirection here...
exit("redirecting to www.{$domains[$key]}");
}
}
}

bOkIcA
18. 03. 2010., 20:02
na 2.000 domena...
~ 0.00103402137756 seconds

bOkIcA
18. 03. 2010., 20:22
Kod svih merenja traženi domen je bio na kraju array-a... ukoliko se domen nalazi na nekom drugom mestu iz petlje se, naravno, izlazi ranije.

bluesman
18. 03. 2010., 23:39
Hvala na trudu i svemu, ali meni je neprihvatljivo rešenje da držim niz od 2000+ domena i radim foreach na svakom page view. Onda ću rađe da napravim jedno opšte pravilo koje važi za većinu a samo izuzetke da tretiram drugačije.

bOkIcA
19. 03. 2010., 00:01
Ok, kapiram.
Ovo je bila samo jedna od "mehničkih" ideja.

I btw. zašto ima potrebe da se na svaki prikaz radi takva provera?
Nije li dovoljno samo jednom pa to zapisati u session i koristiti?

laku noć :)

bluesman
19. 03. 2010., 00:06
Zato što je to prvo što se izvršava, pre svega ... neću da učitavam stranu do pola da bih shvatio da moram da radim redirekciju... ako ću tako, onda mogu i da koristim ovo tvoje rešenje :)

Hoću da izbegnem htaccess da mi ne bi radio rulove za svaki request. Hoću da izbegnem čitanje iz baze po svaku cenu.

miks
19. 03. 2010., 03:12
Na datom linku se nalazi bibliteka/funkcije za dobijanje registrovanog domena

http://www.dkim-reputation.org/regdom-libs/

ako imate registrovani domen, onda poddomen nije tesko pronaci.

razno
19. 03. 2010., 03:38
Nije potreban nikakav niz niti DNS lookup.
ccTLD domen ima maksimalno dva karaktera. Ispred ta dva karaktera ide do cetri znaka tipa info, co, com, biz itd (izvor http://www.entorno.es/dominios_territoriales.php?idioma=eng)
Ja sam pronasao da je info jedini sa cetiri karaktera (U .info.tr), eventualno postoji jos neki koji bi bilo potrebno dodati.

Sledeci kod bi trebalo da prepoznaje sve vrste domena i poddomena, eventualno je potrebna mala modifikacija za jos neki ccTLD koji nisam pronasao.

<?

function transfer($host){
echo "$host ";
$d=explode('.',$host);
$total=count($d);

if($total==3)
{
if(strlen($d[2])==2 && $d[0]!="www")
if(strlen($d[1])==4 && $d[1]=="info")
echo"<b>www.".$d[0].".".$d[1].".".$d[2]."</b>";
elseif(strlen($d[1])<4)
echo"<b>www.".$d[0].".".$d[1].".".$d[2]."</b>";


}
elseif($total==2)//host sa jednom tackom
echo"<b>www.".$d[0].".".$d[1]."</b>";

echo"<br>";
}

transfer("www.domain.com");
transfer("primer.domain.com");
transfer("domain.com");
transfer("www.domain232.com.br");
transfer("primer.domain32423.com.br");
transfer("example2323.com.br");
transfer("www.nesto.rs");
transfer("www.nesto.co.rs");
transfer("nesto.rs");
transfer("nesto.co.rs");
transfer("domen.nesto.rs");
transfer("domen.nesto.co.rs");
transfer("domen.com.hr");
transfer("prvi.domen.com.hr");
transfer("nesto.info.tr");
transfer("www.nesto.info.tr");
transfer("prvi.nesto.info.tr");;

?>


Skripta stampa samo gde treba doci do promene, u mojim primerima izlaz je sledeci

www.domain.com
primer.domain.com
domain.com www.domain.com
www.domain232.com.br
primer.domain32423.com.br
example2323.com.br www.example2323.com.br
www.nesto.rs
www.nesto.co.rs
nesto.rs www.nesto.rs
nesto.co.rs www.nesto.co.rs
domen.nesto.rs
domen.nesto.co.rs
domen.com.hr www.domen.com.hr
prvi.domen.com.hr
nesto.info.tr www.nesto.info.tr
www.nesto.info.tr
prvi.nesto.info.tr


Nadam se da nisam nesto ispustio sobzirom da je kasno i da sam proveo 12 sati na fakultetu :1058:

User
19. 03. 2010., 11:07
https://wiki.mozilla.org/TLD_List

bOkIcA
19. 03. 2010., 17:09
^ onda tu TLD listu da drzite u multidimenzijalnom array-u, lol opet ja i array :D ;)

Aj kad dodjete do nekog resenja da ga objavite ovde, ako ne bude problem.

miks
19. 03. 2010., 19:11
^ onda tu TLD listu da drzite u multidimenzijalnom array-u, lol opet ja i array :D ;)

Aj kad dodjete do nekog resenja da ga objavite ovde, ako ne bude problem.

Resenje vec postoji. Na linku koji sam prethodno postovao mozete naci vise informacija. Poslednja verzija za PHP je prikacena.

dejanr
26. 03. 2010., 13:28
Ja sam uspeo da odradim ovo na nivou web server-a jedan virtual host sa rewrite-om na osnovu toga da li postoji fajl u document_root/domains/imedomena

Posto je vec receno da u bazi drzite imena domena za koje ce raditi aplikacija, prilikom dodavanja, brisanja domena potrebno je i dodati i obrisati fajl u domains/ime_domena.

Tipa ako zelimo da nam aplikacija radi za example.com, samo cu touch-ovati taj fajl:

touch domains/example.com
touch domains/www.example.com
touch domains/test.example.com

Tako da ako posetimo http://example.com, mozemo uraditi sledeci rewrite:

set $postoji 0;

# ako fajl postoji vrati ga odmah i prekini konekciju
if (-f $request_filename) {
break;
}

# ukoliko postoji trazeni domen
if (-f $document_root/domains/$host) {
set $postoji 1;
}

# ukoliko postoji trazeni domen sa www pod domenom
if (-f $document_root/domains/www.$host) {
set $postoji "${postoji}2";
}

# ukoliko ne postoji domen redirektuj na default host
if ($postoji = 0){
rewrite ^(.+)$ http://www.example.com$1 last;
break;
}

# rewrite-uj trazeni domen sa www pod domenom
if ($postoji = 12){
rewrite ^(.+)$ http://www.$host$1 last;
break;
}

Koristim nginx i php fast cgi i evo kako bi to moglo da se resi:

A sve to zajedno za catchall virtual host bi izgledalo ovako:

server {
listen 80 default;
server_name _;
root /Users/dejanr/Sites/dpt;
server_name_in_redirect off;
set $postoji 0;

# ako fajl postoji vrati ga odmah i prekini konekciju
if (-f $request_filename) {
break;
}

# ukoliko postoji trazeni domen
if (-f $document_root/domains/$host) {
set $postoji 1;
}

# ukoliko postoji trazeni domen sa www pod domenom
if (-f $document_root/domains/www.$host) {
set $postoji "${postoji}2";
}

# ukoliko ne postoji domen setuj default host
if ($postoji = 0){
rewrite ^(.+)$ http://www.example.com$1 last;
break;
}

# rewrite-uj trazeni domen sa www pod domenom
if ($postoji = 12){
rewrite ^(.+)$ http://www.$host$1 last;
break;
}

location ~ .php$ {
fastcgi_pass 127.0.0.1:9000;
fastcgi_index index.php;
fastcgi_param SCRIPT_FILENAME $document_root/public$fastcgi_script_name;
include /usr/local/nginx/conf/fastcgi_params;
}
}

bluesman
26. 03. 2010., 13:35
Tnx, ali kod nas svi domeni pucaju na isti docroot. Mada nekako mi je nesigurno da se jedna stvar oslanja na drugu nezavisnu stvar računajući da će sve da bude kako je "logično".

dejanr
26. 03. 2010., 13:39
pa da radi sve za isti document root

dejanr
26. 03. 2010., 14:27
Document Root je u:

root /Users/dejanr/Sites/dpt;

btw ovo moze i da radi kao reverse proxy ka apache-u koji je na drugom ip-u ili port-u. Pri cemu ce sve staticke stvari servirati nginx iz ovog uslova:

# ako fajl postoji vrati ga odmah i prekini konekciju
if (-f $request_filename) {
break;
}

A ostalo biti prosledjeno apache-u koji je zver :)