Feststellen, ob Besucher Deutsch oder Englisch spricht

martinibook

martinibook

Aktives Mitglied
Thread Starter
Dabei seit
20.08.2005
Beiträge
8.730
Reaktionspunkte
350
Hi,

Ich habe eine Webseite, die in Deutsch und Englisch verfügbar ist. Momentan ist am Rand ein Knopf, mit dem man die Sprache umstellen kann.

Wenn jemand aus Deutschland auf die Seite geht, ist das kein Problem, da Deutsch Standard ist. Wenn jetzt jemand aus den USA auf die Seite schaut, bekommt er die Deutsche Version zu Gesicht und kann damit nichts anfangen.

Google leitet mich von google.com immer auf google.de um, irgendwie scheinen die zu wissen, dass ich aus Deutschland komme.

Ich habe keinen Root-Zugriff und möchte auch nichts dafür bezahlen. PHP ist vorhanden.

Eine andere Möglichkeit ist eine Seite davor zu schalten, auf der man die Sprache aussuchen kann.

Geht das einfach automatisch?

Martin
 
short an dirty

Falls deine Seite auf der index.php tanzt und alles über den QUERY_STRING gesteuert wird: am Seitenanfang einsetzen.
PHP:
<?php
	$checkurl = @parse_url ($_SERVER['REQUEST_URI']);

	if (!$checkurl['query'])

	switch (preg_match ('#[\W](de)[\W]#i', $_SERVER['HTTP_USER_AGENT'].'-'.$_SERVER['HTTP_ACCEPT_LANGUAGE'].'-'))
	{
		case true:
		# via QUERY_STRING zur deutschen Version (lang als Sprachvariable angemommen)
		header ('refresh: 0; url='.$_SERVER['PHP_SELF'].'?lang=de');
		break;
		
		default:
		# via QUERY_STRING zur englischen Version (lang als Sprachvariable angemommen)
		header ('refresh: 0; url='.$_SERVER['PHP_SELF'].'?lang=en');
		break;
	}
?>
Falls du eine index.php vorschalten willst, dann ist das der Inhalt der index.php.
PHP:
<?php
	switch (preg_match ('#[\W](de)[\W]#i', $_SERVER['HTTP_USER_AGENT'].'-'.$_SERVER['HTTP_ACCEPT_LANGUAGE'].'-'))
	{
		case true:
		header ('refresh: 0; url=./(dein relativer Pfad zur deutsche Version z.B. de.php)');
		break;
		
		default:
		header ('refresh: 0; url=./(dein relativer Pfad zur englische Version z.B en.php)');
		break;
	}
?>
Eine index.html darf in beiden Fällen natürlich nicht existieren. Wie der Google-Bot drauf reagiert, kann ich dir nicht sagen, eventuell nimmt er die Umleitung übel. Melde deine Seite am besten bei google webmasters tools an, und beobachte was passiert.

Kurze Erklärung: Untersucht wird die Browser-Kennung ($_SERVER['HTTP_USER_AGENT']) plus Sprachversionen des Browsers ($_SERVER['HTTP_ACCEPT_LANGUAGE']). Wird in dieser Kombination "de" gefunden, dann wird "deutsch" ermittelt - angenommen der Besucher benutzt die kranke Windows-Version von Safari 3.0.1 und die kombinierte Kennung ist Mozilla/5.0 (Windows; U; Windows NT 5.1; de) AppleWebKit/522.12.1 (KHTML, like Gecko) Version/3.0.1 Safari/522.12.2-en-, dann sagt das Script "kommt mit bekannt vor, muss ein kranker Deutscher sein"; sollte er hingegen mit einem nicht-deutschsprachigen Netscape 4 unterwegs sein "Mozilla/4.8 [en] (Windows NT 5.0; U)-en-", dann ist er :hamma: abnormal und krank. :Oldno: - und, Verzeihung, ab diesem Moment englisch.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: martinibook und ThaHammer
Bitte trotzdem die Möglichkeit einbauen manuell auf eine andere Sprache umzustellen, da manche einen englischen Browser verwenden, und trotzdem in der Lage sein möchten auf deutsch zu lesen *g*
 
  • Gefällt mir
Reaktionen: HerrSchnuff
Ja, so war das in beiden Fällen auch gedacht.
Ich habe eine Webseite, die in Deutsch und Englisch verfügbar ist. Momentan ist am Rand ein Knopf, mit dem man die Sprache umstellen kann.
Und das sollte auch so bleiben. Das beste wäre natürlich ein Link, um sich die Seite mal anzuschauen.

Es gäbe noch eine kürzere Variante für den ersten Fall. Voreingestellt ist deutsch, d.h. keine Umleitung.

Tanz auf der Index.php
PHP:
<?php 
    $checkurl = @parse_url ($_SERVER['REQUEST_URI']); 

    # if (!$checkurl['query'])  

    if (!$checkurl['path'] || $checkurl['path'] == '/') 
    // So spräche der Besucher die Umleitung nur an, wenn  
    // http://domainname.tld oder http://domainname.tld/  
    // aufgerufen wird 

    switch (preg_match ('#[\W](de)[\W]#i', $_SERVER['HTTP_USER_AGENT'].'-'.$_SERVER['HTTP_ACCEPT_LANGUAGE'].'-')) 
    { 
        case false: 
        // via QUERY_STRING zur englischen Version  
        // (lang als Sprachvariable angemommen) 
        header ('refresh: 0; url='.$_SERVER['PHP_SELF'].'?lang=en'); 
        break; 
    } 
?>
Es muss nur dafür gesorgt sein, dass beim "Wechsel von der englischen zur deutschen Version" nicht einfach http: //domainname.tld oder http: //domainname.tld/ sondern http: //domainname.tld/index.php aufgerufen wird, oder, wenn $checkurl['query'] abgefragt wird, dann muss ein Parameter dran. http: //domainname.tld/?d für den Deusch-Button reichte aus, der Parameter spielt keine Rolle, er muss nur vorhanden sein.

Da die Umleitung passiert, bevor der Besucher bookmarken kann, kann ein Besucher mit "nicht-deutschem" Browser, natürlich die deutsche Version per Button wählen (falls sein englischer Browser s. Beispiel Safari 3.0.1 überhaupt als "nicht-deutsch" identifiziert wird) und dann seine Bookmark setzen. Und natürlich könnte man die Sprachwahl noch in ein COOKIE schreiben, dass zur letztaufgerufenen Version lenkt.
 
Zuletzt bearbeitet:
Momentan habe ich es so, dass im / eine index.php liegt, die einfach nur per header(location:site/index.php); auf die Seite weiterleitet.

Die Sprache habe in einer Session abgelegt. Wenn man auf den Knopf für den Sprachenwechsel klickt, öffnet sich eine andere Seite, die die neue Sprache in die Session einträgt und wieder zurück weiterleitet.

Die Sprache wird also nicht immer weitergegeben und steht in der Session. Das bedeutet allerdings auch, dass die Sprache nicht im GET drin steht, also auch nicht im Lesezeichen auftaucht. Das ist sicher nicht gut.

UDH5, dein kleines Skript schaut sich also die Browserkennung an und schaut, ob ein "de" darin vorkommt, sehe ich das richtig? Das ist ja dann wirklich keine Hexerei.

Vielen Dank für das Skript, ich werde es mal einbauen.

Wie funktioniert das mit den Regulären Ausdrücken, also was beutet # und \w?
 
Zuletzt bearbeitet:
Ob # oder / als Einfassung der RegExp ist egal, solange das Zeichen in in der RegExp nicht vorkommt, erspart es einfach nur Backslashes.
\W bedeutet any "non-word" character und ist das Gegenteil von \w http://www.php.net/manual/de/reference.pcre.pattern.syntax.php

Der URL für deutsch/englisch ist der gleiche und die Session entscheidet, welche Sprache gewählt ist? Heißt das, zu einer deutschen Seite gibt es immer das englische Pendant?

Das mit dem Bookmarken und dem fehlenden Get-Parameter stimmt, käme natürlich auf die Zahl der Dateien an bzw., ob du mit einem Text-Generator einfach über Suchen und Ersetzen das ganze Verzeichnis rekursiv bearbeiten kannst. Dann würde ich dir empfehlen die Sprachsteuerung in einer include-Datei zu definieren - gedeutet: einmal Arbeit mit vielen Dateien.

Aber wenn dir das zu aufwendig erscheint, ich glaube es würde mich nicht stören, auf den nebenstehenden Sprachbutton zu klicken, sobald ich am Inhalt der gebookmarkten Seite interessiert bin.

Wenn der Sprachwechsel nur über die Einstiegsseite geht, ist das natürlich etwas anderers - dann bleibt dir die Qual der Wahl - da würde ich den zusätzlichen GET-Parameter zum Bookmarken allerdings vorziehen.

<klugs...mode>GET-Parameter immer überprüfen, register_globals ist nicht genug. Also: default deutsch und, wenn korrekt übergeben, englisch - hab selbst schon Bekannten im Rahmen einer Überprüfung einen manipulierten URL ihrer Website mit zusätzlichen Style-Sheets und eingebauten Googlebildern geschickt. Macht sich nicht gut, wenn man im Internet einen solchen Link angeboten bekommt. Und benutze error_reporting(0) bei einer fertigen Website, ich finde es schrecklich, wenn jedem Besucher in PHP-Fehlermeldungen die Server-Struktur offenbart wird</klugs...mode>
 
Ich habe das jetzt so umgestellt, dass die Sprache immer per GET übergeben wird. Alle URLs sehen jetzt so aus:
/site/index.php?lang=de&hk=3&sk=kontakt

in der /site/index.php sieht es dann so aus.
Code:
$lang = $_GET['lang'];
if ($lang != 'de' && $lang != 'en')
	$lang = 'de';
	
$hk = $_GET['hk'];
$sk = $_GET['sk'];

Die Sprachwahl entscheidet sich in der /index.php, man kann aber nachher immer noch wählen.

Das mit dem error_reporting(0) ist ein netter Tip, danke.
 
PHP:
$lang = ($_GET['lang'] != 'en') ? 'de' : 'en';
Nur der Schönheit halber. Du hast ja offensichtlich eine gut strukturierte Website, wenn es so schnell ging.

Ach so, wenn $hk immer integer ist, dann $hk = ((int)$_GET['hk']) ? (int)$_GET['hk'] : 0; und 0 heißt einfach nur zurück zum Start, dann kann dir niemand was reinbasteln.

Sorry, Quatsch - $hk = (int)$_GET['hk']; reicht.
 
Zuletzt bearbeitet:
Bedingte Zuweisung, ja, das ist fast genauso wie:

arrayCopy (*a, *b)
{
while (*a++ = *b++);
}

;)

Danke für die Blumen!
 
gelöscht
 
Zuletzt bearbeitet:
Tja, billig ist ist auf jedenfall richtig.
 
Wie kommt ihr denn jetzt plötzlich auf Java?

Die Webseite ist in PHP geschrieben und mein arrayCopy-Beispiel sollte C sein.
 
Wie kommt ihr denn jetzt plötzlich auf Java?
Die Webseite ist in PHP geschrieben und mein arrayCopy-Beispiel sollte C sein.
Sorry, hatte bei arrayCopy auf Java getippt - war gestern ein bisschen überarbeitet. Ich lösch das Posting, war sowieso blödsinnig.
 
In Java gibt es keine echten Pointer, es gibt nur CallByValue bei einfachen Daten wie int, char, double und CallByReference wenn es sich um ein Objekt handelt. Aber eingreifen wie in C geht nicht. Das vereinfacht das meiner Meinung nach und andere sagen, man hätte doch jetzt das beste an C nicht mehr.
 
PHP:
$lang = ($_GET['lang'] != 'en') ? 'de' : 'en';

Nur nochmal kurz zur bedingten Zuweisung im Zusammenhang mit Zeiger und Referenzierung. $lang ist ja hier kein Zeiger auf $_GET['lang'] d.h. $_GET['lang'] wird nicht referenziert und verändert, es wird nur ausgewertet und das Ergebnis in $lang gespeichert.

Sofern nicht register_globals = On ist, gibt es zwischen $_GET['lang'] und $lang also keinen anderen Zusammenhang als den Wertetest.
 
Warum diese Überprüfungen der Variablen? Nur um den Fehler 404 zu vermeiden?

Als in PHP die Superglobals eingeführt wurden, tauchte ja bei bestehenden Websites die Frage auf: "Wie kriege ich das hin, ohne die Site komplett umzugraben". Und: "Was ist, wenn z.B. sowohl $_POST['lang'] als auch $_GET['lang'] einen Wert für $lang liefern können"; die Lösung war pt_register - das Original-Script bzw. den Author hab ich leider nie gefunden, vielleicht kann mir ein MU ja auf die Spünge helfen, ich würde ihn gerne nennen.

3. Create a global.inc.php file -> Privacy Feature, Here's the code. [#93981] | Drupal.org

'SESSION' ist überflüssig, da sich $_SESSION nicht einfach globalisieren lässt, und eine Fehlermeldung ausgibt, solange man nicht ini_set ('session.bug_compat_warn', 'off'); verwendet.

Das Script ist aber nicht nur für Faule, wenn man es etwas erweitert, dann kann man an dieser Stelle einem anderen, und immer aktuellen, Problem ganz gut begegnen - auf den Punkt gebracht von Kristian Köhntopp: Traue niemandem. Validiere allen Input oder stirb. FAQ der Newsgroups de.comp.lang.php.* - 12.11. Prüfe importierte Parameter. Traue niemandem

Die Orignal-Funktion pt_register braucht mindestens zwei Parameter ('METHODE', 'variable') wenn man auch auf die Überprüfung des Variablentyps Wert legt, dann könnte man noch einen dritten notwendigen Parameter einführen. Die komplette Funktion sähe dann so aus. (die Kommentare für den Documentor kriege ich im Forum nicht richtig hin, weil sie ohne Leerzeichen rausgestrippt werden - Leerzeichen zwischen / und * entfernen)

PHP:
<?php    
    / **
    * Hier werden die Methoden: GET, POST, SERVER, COOKIE, ENV und FILE registriert
    * und Variablen methodengerecht übergeben, wenn in der php.ini register_globals = Off steht.
    * D.h., anstelle von $_GET['x'] kann $x benutzt werden.
    * Auf Methode folgt ein zweites Argument, das über die Art der variable Auskunft gibt,
    * zur Zeit nur 'n' integer, 'a' sonstiges und 'r' array()
    *
    * @package        Webpage
    * @module        register_globals
    * @modulegroup    var_sniffer
    */

    / **
    * meldet GET, POST, SERVER, COOKIE und ENV Variablen an
    *
    * @access public   
    * /
    function pt_register()
    {
        $num_args = func_num_args();
       
        $vars = array();
       
        if ($num_args >= 3)
        {
            $method = strtoupper (func_get_arg (0));
           
            if (($method != 'GET') && ($method != 'POST') && ($method != 'SERVER') && ($method != 'COOKIE') && ($method != 'ENV'))
            {
                die ('Argument 1 fehlt: GET, POST, SERVER, COOKIE, oder ENV');
            }

            $type = strtolower (func_get_arg (1));

            $varname = '_'.$method;
           
            global ${$varname};
           
            for ($i = 2; $i < $num_args; $i++)
            {
                $parameter = func_get_arg ($i);
               
                if (isset (${$varname}[$parameter]))
                {
                    global $$parameter;
                   
                    switch ($type)
                    {
                        case 'n':
                       
                        $$parameter = @(int)${$varname}[$parameter];
                       
                        break;
                       
                        case 'r':
                       
                        $$parameter = (@is_array (@${$varname}[$parameter])) ? ${$varname}[$parameter] : array();

                        break;
                   
                        default:
                       
                        $$parameter = @${$varname}[$parameter];
                       
                        break;
                    }
                }
            }
        }
        else
        {
            die ('Mindestens 3 Argumente!');
        }
       
    }
   
    / **
    * meldet FILE Variable an
    *
    * @access public   
    * /
    function pt_registerFILE()
    {
        $num_args = func_num_args();
       
        for ($i = 0; $i < $num_args; $i++)
        {
            $parameter = func_get_arg($i);
           
            if (isset ($_FILES[$parameter]))
            {
                global $$parameter;
               
                $$parameter = $_FILES[$parameter]['tmp_name'];
            }
        }
    }
?>
Aufruf-Beispiel
PHP:
    # > register globals
   
    pt_register
    (
        'POST', 'n', 
        'submitted', 'kg', 'a_id', 't_id', 'wkb', 'setcook', 'artikel_id', 'gesendet', 'page', 'formspalte'
    );
   
    pt_register
    (
        'POST', 'a', 
        'form_id', 'kennung', 'formularkennung', 'zusatz', 'set_lang', 'lang', 'rsv_id'
    );
   
    pt_register
    (
        'POST', 'r', 
        'newsletter', 'formular', 'log', 'wk', 'sitesearch', 'sitesearchoption', 'sitesearchorder'
    );

    pt_register
    (
        'GET', 'n', 
        'vret', 'kdl', 'adl', 'sdl', 'ldl', 'mdl', 'rdl', 'dlh', 'bak', 'wkb', 'srch', 'httpv', 'mes',
        'kg', 'flash', 'r_id', 's_id', 'v_id', 'a_id', 't_id', 'lang', 'arch', 'gesendet', 'vcl', 'tab'
    );
   
    # < register globals
Die vielen @ sollen nur verhindern, dass bei eingeschaltetem error_reporting (E_ALL) undefined index auftaucht und dadurch den gesamten Scriptablauf durch Cannot modify header information - headers already sent korrumpiert. Typ 'a' ist also der unsicherste, und müsste je nach Website mit anderen Funktionen überprüft werden. Wenn aber Navigationsvariablen vom Typ 'n' wie IDs oder 'r' für die Darstellbarkeit entscheidend sind, dann fällt dieses Manko eventuell nicht so sehr ins Gewicht.

Und warum nochmal der der Aufwand, obwohl das Script ja für Faule gedacht ist? Jeder, der selbst (PHP)? Programme ins Netz stellt, sollte sich auch um die Sicherheit seiner Konstruktionen Gedanken machen, und auch an diejenigen denken, die sich im großen Supermarkt Internet nur bedienen. Dann wird das Geschäft für die bösen Hacker vielleicht auf Dauer unlukrativ. Und ja, ich gebe zu, dass das eine Art Aufruf zur Verbesserung des Internets ist (jenseits aller W3C-Regeln) ... und ich bin bin in dieser Angelegenheit auch nur ein Anfänger.
 
Zuletzt bearbeitet von einem Moderator:
Und zu guter Letzt noch ein Tipp für 1und1 Benutzer, auf den ich nach langer Suche eher zufällig gestoßen bin. Man kann eine Datei namens php.ini in das DOCUMENT_ROOT Verzeichnis legen und z.B. anweisen
Code:
register_globals = Off
safe_mode = On
session.use_trans_sid = On
post_max_size = 60M
upload_max_filesize = 20M
max_execution_time = 480
max_input_time = 480
memory_limit = 20M
Man kann darüberhinaus auch DOCUMENT_ROOT eine Ebene tiefer legen und Webspace schaffen, der nicht über das http-Protokoll zugänglich ist - Stichwort: lib, include-Daten.

Bei anderen Providern wie arcor.net auf keinen Fall php.ini genauso anwenden, sie ergänzt nicht, sondern überschreibt.
 
Zuletzt bearbeitet:
  • Gefällt mir
Reaktionen: Olivetti
Ich habe nicht so viel Ahnung von PHP. Das erfreuliche ist, dass Input eigentlich nur als Parameter für den Seiteninhalt erfolgt, also die Kategorie und Sprache. Sprache ist durch die bedingte Zuweisung ja eigentlich geregelt. Neulich zeigte mir ein Freund den \0 Bug, mit dem man Strings vorzeitig beenden kann.

Danke für den Link, das Prüfen mit den Listen werde ich mir zu Herzen nehmen.
 
Ich habe noch eine Frage:
Ich brauche irgendwie einen Test darauf, ob eine Zeichenkette entweder eine Zahl ist, oder ausschließlich aus Buchstaben besteht.

Wie geht das?
 
Zurück
Oben Unten