Verwendung von Server-Variablen
Frederic
- php
- webserver
Hallo,
ich definiere in der .htaccess
SetEnv MyAkt_spr e
SetEnv MyAkt_.....
...............
Wenn ich mir die Variablen mit phpinfo.php anzeigen lasse, so gibt es große Unterschiede, je nachdem bei welchem Provider dieses .htaccess verwendet wird (siehe Anlage). Ich möchte nach Möglichkeit in den PHP-Programmen, die auf den drei Servern die gleiche Funktionen haben nicht unterschiedliche Variablennamen verwenden. Wie könnte ich dies auf einfache Weise erreichen?
$_ENV
gibt es in manchen modernen PHP-Installationen (Hier PHP 7.0 als php_cli und als Apache-Modul ausgeführt) nur als leeres Array.
Du greifst also am besten immer über $_SERVER['MyAkt_Dir']
zu.
Was mir nicht eingeht, ist, warum Du (angeblich) 'MyAkt_spr' setzt und 'MyAkt_Dir' herausbekommen solltest. Das ist schlicht unmöglich und hier vermute ich den Fehler bei Dir.
Dann wäre da noch eine Vermutung:
Womöglich stellst Du Dich in PHP mit ETWAS wie
define ( 'DOCUMENT_ROOT', realpath( $_SERVER['DOCUMENT_ROOT'] ) );
besser. (dokumentation: realpath)
$_ENV gibt es in manchen modernen PHP-Installationen (Hier PHP 7.0 als php_cli und als Apache-Modul ausgeführt) nur als leeres Array.
grep 'variables_order' /etc/php/*/*/php.ini
(in einer Shell ausgeführt) sagte mir gerade, dass das „E“ in der Einstellung für variables_order fehlt. Die Einstellung des Distributors (oder von den PHP-Machern) steht auf "GPCS". Setzt man es auf "EGPCS", dann wird $_ENV
gefüllt. Aber das ist nicht notwendig, denn es gibt $_SERVER
.
@Regina: Sollte natürlich immer MyAkt_spr heißen.
@Felix: Abhängig von MyAkt_spr sollen verschiedensprachige Texte verwendet werden. Die zugrundeliegenden PHP-Programme sollen identisch sein. Ähnliche Funktionen haben die anderen Variablen, wie MyAkt_dir, u.a. Damit im Programm nicht die langen Angaben $_SERVER..... verwendet werden müssen, diese Kurzbezeichnungen. Und jetzt kommt noch hinzu, dass die gleichen Programme auf unterschiedlichen Servern (Providern) laufen sollen. Und da gibt es die o.g. Unterschiede : $_SERVER['MyAkt_spr'] bzw. $_SERVER['REDIRECT_MyAkt_spr']
hi,
Und da gibt es die o.g. Unterschiede : $_SERVER['MyAkt_spr'] bzw. $_SERVER['REDIRECT_MyAkt_spr']
Beide Variablen müssten eigentlich beide vorhanden sein, also einmal mit REDIRECT_ Prefix und einmal ohne, sofern Rewrite On gesetzt ist. Zumindest ist das bei mir der Fall.
MfG
Meintest Du "RewriteEngine On"? Dies ist in allen drei oben beschriebenen Varianten gesetzt.
Hi,
mach dochmel einen Dump dann siehst Du doch was gesetzt ist. In meinem Beispiel SetEnv ASDF 123flitz
MfG
Abhängig von MyAkt_spr sollen verschiedensprachige Texte verwendet werden.
Naja. Das geht wohl besser:
über die Definition einer Konstanten
define ('LANG', 'DE_de');
oder besser noch über eine Klasse bzw. ein Objekt.
Damit im Programm nicht die langen Angaben $_SERVER..... verwendet werden müssen, diese Kurzbezeichnungen.
Das ist wirklich keine gute Idee. Aber das lernst Du bestimmt noch. Nämlich bei der Fehlersuche. Und dann lernst Du auch die wunderbaren Kopierfunktionen Deines Editors zu benutzen und ganz sicher auch den Umstand zu schätzen, dass $_SERVER ein Superglobal ist.
Das hab ich nämlich auch am sehr praktischen Beispiel meiner eigenen Versuche gelernt.
Kann ich die Konstanten in .htaccess definieren? Die PHP-Funktionen, die diese benutzen sollen nämlich alle identisch sein. Ich kann also nicht in HP-Programmen die Konstanten setzen.
Die PHP-Funktionen, die diese benutzen sollen nämlich alle identisch sein. Ich kann also nicht in HP-Programmen die Konstanten setzen.
Umgebungsvariablen sind dafür schon die zu bevorzugende Lösung. Leider gibt es einen Bug in Apache, der den unliebsamen Prefix nach internen Rewrites hinzufügt. Im verlinkten Stackoverflow-Beitrag werden einige Workarounds über die Apache-Konfiguration erklärt. Alternativ hilft dagegen auch ein PHP-Workaround, irgendwie sowas:
function getEnvironmentVariable ($name, $fallback = '') {
return $_SERVER[$name] ?? $_SERVER["REDIRECT_${name}"] ?? $fallback;
}
Lieber Frederic,
Kann ich die Konstanten in .htaccess definieren?
was hindert Dich daran, zu Deinem PHP-Code noch eine Konfigurationsdatei zu speichern, die nicht .htaccess
, sondern vielleicht config.xml
heißt? Mit simplexml_load_file()
kann man das wunderbar auslesen.
Die PHP-Funktionen, die diese benutzen sollen nämlich alle identisch sein.
Klar, näheres regelt eine Konfigurationsdatei. Aber nicht .htaccess
! Davon lässt Du lieber die Finger, denn für Dein PHP-Programm ist sie nicht gedacht.
Ich kann also nicht in HP-Programmen die Konstanten setzen.
Doch, kannst Du. Nur welche Werte sie bekommen, regelst Du in Deiner Konfigurationsdatei.
Liebe Grüße,
Felix Riesterer.
was hindert Dich daran, zu Deinem PHP-Code noch eine Konfigurationsdatei zu speichern, die nicht
.htaccess
, sondern vielleichtconfig.xml
heißt? Mitsimplexml_load_file()
kann man das wunderbar auslesen.
Kann man auch so machen, ist aber mehr Aufwand als Umgebungsvariablen und dadurch gewinnt man nicht viel. Mit simplexml_load_file()
bist du ja noch nicht am Ende, du musst ja noch die einzelnen Werte aus dem DOM-Baum holen.
Die PHP-Funktionen, die diese benutzen sollen nämlich alle identisch sein.
Klar, näheres regelt eine Konfigurationsdatei. Aber nicht
.htaccess
! Davon lässt Du lieber die Finger, denn für Dein PHP-Programm ist sie nicht gedacht.
Umgebungsvariablen sind sogar genau dafür gedacht. Bei Apache konfiguriert man diese nunmal in der .htaccess-Datei oder der VHost-Konfiguration oder der globalen Webserver-Konfiguration. Siehe auch den Link, den ich unter mein anderes Anwort-Posting gesetzt habe. TL;DR: Umgebungsvariablen sind sprach- und systemunabhängig, orthogonal zueinander und landen nicht versehentlich im Code-Repostory.
Dateibasierte Konfiguration kann man wunderbar zusätzlich dazu einsetzen, für Einstellungen, die nicht zwischen verschiedenen Servern variieren sollen, bspw. die Routing-Tabelle. So lassen sich die serverspezifischen und -agnostischen Einstellungen sauber voneinander trennen.
Zudem ist diese Trennung recht weit verbreitet in der Server-Programmierung, einige Frameworks basieren darauf. Auch wenn du sie jetzt für deinen Anwendungsfall als ungeeignet empfindest, so ist es doch ein anerkanntes Best Practice. Die Einschätzung die Finger davon zu lassen, kann ich daher nicht teilen.
was hindert Dich daran, zu Deinem PHP-Code noch eine Konfigurationsdatei zu speichern, die nicht .htaccess, sondern vielleicht config.xml heißt? Mit simplexml_load_file() kann man das wunderbar auslesen.
Kann man auch so machen, ist aber mehr Aufwand als Umgebungsvariablen und dadurch gewinnt man nicht viel. Mit simplexml_load_file() bist du ja noch nicht am Ende, du musst ja noch die einzelnen Werte aus dem DOM-Baum holen.
Eben. Für vergleichbar einfache Wertsetzungen gibt es parse_ini_file();
und die Schwester parse_ini_string();
. Den übernommenen Array kann man in ein Objekt übernehmen, es kann auch eine globale Variable sein: (Achte auf die Prüfung, damit Du Fehlermeldungen bekommst.)
<?php
# file: myIniRead.php
function myIniRead() {
$iniString '';
$iniFiles = ['/data/server.ini', '/data/site.ini'];
foreach ( $iniFiles as $ini ) {
$ini = $_SERVER['DOCUMENT_ROOT'] . $ini ;
if ( is_file ( $ini ) ) {
if ( is_readable ( $ini ) ) {
$iniString .= file_get_contents ( $ini) . "\n";
} else {
trigger_error ( "Fatal: $ini nicht lesbar (Rechte?)", E_USER_ERROR );
}
} else {
trigger_error ( "Fatal: $ini existiert nicht", E_USER_ERROR );
}
}
return parse_ini_string( $ini );
}
$GLOBALS['config'] = myIniRead();
Dazu noch ein Hinweis: Eigentlich sollte der Ordner /data AUSSERHALB des Document-root liegen, damit er nicht versehentlich ausgeliefert wird und dann z.B: Zugangsdaten zur Datenbank sichtbar werden. Im Beispiel habe ich das anders gemacht, weil manche Billig-Hoster diese Möglichkeit nicht bieten.
In dem Fall sollte (auf einem Apache Webserver) wenigstens eine Datei mit dem Name ".htaccess" existieren (wenn wenigstens das erlaubt ist), welche den Zugang sperrt. Minimallösung: Die Dateinamen beginnen mit ".ht".
Nutzung:
Obiges Skript wird einfach mit require_once()
eingebunden:
<?php
require_once ( $_SERVER['DOCUMENT_ROOT'] . '/myIniRead.php' );
Der Zugriff geht dann in Funktionen wie folgt:
function configDebug () {
if ( isset ( $GLOBALS['config'] ) ) {
print "<pre>";
var_dump( $GLOBALS['config'] );
print "</pre>";
} else {
print '<pre>$GLOBALS[config] ist nicht besetzt.</pre>';
}
}
configDebug ();
Eine solche Datei, welche die Konfiguration anzeigt, sollte auch nicht für jeden abrufbar sein.
Obiges hat, weil einfach mal hier niedergeschrieben, kleinere Fehler. Deshalb habe ich die lauffähig gemachten und im Detail verbesserten Versionen einfach mal auf meinen Home-Server abgelegt:
Test: https://home.fastix.org/Tests/iniRead/configDebug.php
Download: https://home.fastix.org/Tests/iniRead/iniRead.tar.gz
Lieber 1unitedpower,
Die Einschätzung die Finger davon zu lassen, kann ich daher nicht teilen.
in den letzten Jahren habe ich schon die tollsten Sachen im Bereich shared webhosting erlebt. Was welcher Anbieter zulässt, dass Du in einer .htaccess
machen darfst, oder ob Du überhaupt eine verwenden darfst, war ein wilder Dschungel an Varianten und (Un)Möglichkeiten. Wie das heute im Schnitt aussieht, vermag ich nicht zu sagen. Daher bleibe ich bei meiner Aussage, da sie unter allen Umständen nutzbar ist und funktioniert.
Liebe Grüße,
Felix Riesterer.
Hi Felix,
dem kann ich nur zustimmen. Eines der vielen Motive warum Frameworks entwickelt werden, besteht nämlich darin, diese von Serverkonfigurationen möglichst unabhängig zu machen. Das heißt also auch, daß man unter einer Vielfalt an Konfigurationsmöglichkeiten eben möglichst den kleinsten gemeinsamen Nenner findet, der portierbar ist, sich also ohne Umschweife auf anderen Systeme einrichten lässt.
Die Serverumgebung schließlich dient dazu, sämtliche Parameter eines Requests für nachgelagerte Prozesse verfügbar zu machen, das ist Sache des Webservers und von daher ist es keine gute Idee, da einzugreifen.
Der OP möchte über eine Konfigurationsdatei nachdenken und gut ist. MfG
Der OP möchte über eine Konfigurationsdatei nachdenken und gut ist.
"So isses!" - Was nämlich wenn der nächste Server ein ngnix ist?
Der OP möchte über eine Konfigurationsdatei nachdenken und gut ist.
"So isses!" - Was nämlich wenn der nächste Server ein ngnix ist?
Das ist ein Nachteil der Umgebungsvariablen: Man braucht die nötige Erfahrung auf jedem System, auf dem man die Webanwendung laufen lassen möchte, oder man muss sich zumindest Einlesen. Dafür glänzen Umgebungsvariablen bspw. auf Container-Infrastukturen, wie Kubernetes, die einen immer größeren Teil moderner Webseiten hosten.
Lieber 1unitedpower,
Das ist ein Nachteil der Umgebungsvariablen: Man braucht die nötige Erfahrung auf jedem System, auf dem man die Webanwendung laufen lassen möchte, oder man muss sich zumindest Einlesen.
der OP macht mir nicht gerade den Eindruck, als hätte er diese Erfahrung. Oder warum sonst hat er diesen Thread gestartet?
Dafür glänzen Umgebungsvariablen bspw. auf Container-Infrastukturen, wie Kubernetes, die einen immer größeren Teil moderner Webseiten hosten.
Klar, und ich als Kunde eines shared webhosting-Angebotes habe da die passenden Stellschrauben zur Verfügung. Da empfinde ich eine Konfigurationsdatei, die mein Programm ausliest, als wesentlich pflegeleichter.
Liebe Grüße,
Felix Riesterer.
Der OP möchte über eine Konfigurationsdatei nachdenken und gut ist.
"So isses!" - Was nämlich wenn der nächste Server ein ngnix ist?
Eben. Man nehme die entsprechende API, genauso wie man das vor 20 Jahren auch schon gemacht hat. Das ist ja der Sinn von Schichtenmodellen, eben diese Schichten transparent zu machen. So gibt es auf Entwicklerseite (Perl, PHP, Python..) nicht einmal mehr das Protokoll HTTP sondern nur noch Methoden um Cookies, Parameter abzufragen also das zu bekommen was der Request so mit sich bringt.
MfG
Lieber Frederic,
ich definiere in der .htaccess
SetEnv MyAkt_spr e SetEnv MyAkt_..... ...............
was ist das eigentliche Problem, das Du damit zu lösen versuchst?
Liebe Grüße,
Felix Riesterer.
Hallo Felix, hallo Frederic,
wie wir mittlerweile wissen: Sprache.
Aber ich frage mich: Warum legt der Server den Wert des Sprachenschalters fest? Muss das nicht der Client tun?
Rolf
Warum legt der Server den Wert des Sprachenschalters fest? Muss das nicht der Client tun?
Erst der Server (Server-Default), dann wird das eventuell mit den Einstellungen des Clients überschrieben, dann mit der Wahl des Benutzers.
https://code.fastix.org/Projekte/PHP%3ALanguageSelector/ (Test)
Lieber Rolf,
Aber ich frage mich: Warum legt der Server den Wert des Sprachenschalters fest? Muss das nicht der Client tun?
da gab es mal einen Feature-Artikel dazu. Mittlerweile ist der nur noch bei Archive.org zu finden.
Liebe Grüße,
Felix Riesterer.
Hallo,
gibt es eine Variable, die angibt, auf welchem Server ich mich befinde oder eine Abfrage, die mir sagt, ob $_SERVER['REDIRECT_MyAkt_spr'] existiert?
In beiden Fällen könnte ich dann doch einfach schreiben if (obige Bedingung) $_SERVER['MyAkt_spr'] = $_SERVER['REDIRECT_MyAkt_spr'];
Was spricht dagegen?
gibt es eine Variable, die angibt, auf welchem Server ich mich befinde oder eine Abfrage, die mir sagt, ob $_SERVER['REDIRECT_MyAkt_spr'] existiert?
Ich halte die zweite Möglichkeit für besser, du kannst den Test mit isset($_SERVER['REDIRECT_MyAkt_spr'])
machen.
In beiden Fällen könnte ich dann doch einfach schreiben if (obige Bedingung) $_SERVER['MyAkt_spr'] = $_SERVER['REDIRECT_MyAkt_spr'];
Was spricht dagegen?
Das $_SERVER
-Array ist ein Sonderfall einer globalen Variablen, die von PHP mit Werten gefüllt wird. ProgrammiererInnen haben bestimmte Erwartungen, was da drin zu stehen hat und was nicht. Wenn du schreibend darauf zugreifst, dann sind diese Erwartungen nicht mehr erfüllt. Im konkreten Fall fände ich es trotzdem legitim, weil du damit eher die Erwartungen der ProgrammiererInnen wiederherstellst, die zuvor von Apache torpediert wurden. Zusätzlich könntest du dir noch überlegen, ob du die geprefixten Einträge auch aus dem Array löschst. Damit hätte jeder Wert nur einen Schlüssel und nicht zwei.
Klappt wunderbar! Mich würde interessieren, was die Erfinder der vorgestellten komplexen Lösungen dazu meinen?
Klappt wunderbar! Mich würde interessieren, was die Erfinder der vorgestellten komplexen Lösungen dazu meinen?
Die kleine Lösung löst Dein unmittelbares Problem auf eine sehr effektive Weise. Die "komplexen" Lösungen sind solche für Probleme, die Dir nur noch nicht bewusst sind.
Eine kitzekleine Änderung an der Lösung von 1unitedpower hätte ich aber noch anzubringen:
function getEnvironmentVariable ($name, $fallback = false) {
return $_SERVER[$name] ?? $_SERVER["REDIRECT_${name}"] ?? $fallback;
}
Damit lässt sich durch einen strikten Vergleich:
if ( ! false === getEnvironmentVariable( 'foo' ) ) {
...
} else {
}
einfacher unterscheiden, ob $_SERVER['irgendwas'] oder $_SERVER['REDIRECT_irgendwas'] einfach nur leer sind oder ob beide gar nicht existieren.
Eine kitzekleine Änderung an der Lösung von 1unitedpower hätte ich aber noch anzubringen:
function getEnvironmentVariable ($name, $fallback = false) {
if ( isset ($_SERVER[$name] ) ) {
return $_SERVER[$name];
} elseif ( isset ( $_SERVER["REDIRECT_${name}"] ) ) {
return $_SERVER["REDIRECT_${name}"];
} else {
return $fallback;
}
}
Damit lässt sich durch einen strikten Vergleich:
if ( ! false === getEnvironmentVariable( 'foo' ) ) {
...
} else {
}
einfacher unterscheiden, ob $_SERVER['irgendwas'] oder $_SERVER['REDIRECT_irgendwas'] einfach nur leer ( NULL
, '', 0 oder FALSE
) sind oder ob beide gar nicht existieren.
Klappt wunderbar! Mich würde interessieren, was die Erfinder der vorgestellten komplexen Lösungen dazu meinen?
Die kleine Lösung löst Dein unmittelbares Problem auf eine sehr effektive Weise. Die "komplexen" Lösungen sind solche für Probleme, die Dir nur noch nicht bewusst sind.
Eine kitzekleine Änderung an der Lösung von 1unitedpower hätte ich aber noch anzubringen:
Ich kann den Wunsch verstehen, persönlich würde ich dann aber eine neue Funktion schreiben. Im Iealfall erledigt eine Funtkion genau eine Aufgabe. Gegen das Prinzip habe ich mit meinem Code aber auch selber verstoßen: Die Funktion liest und gibt beim Scheitern eine Fallback-Wert zurück. Besser wäre sowas:
function getEnvironmentVariable (string $name) : string {
return $_SERVER[$name] ?? $_SERVER["REDIRECT_${name}"] ?? '';
}
function issetEnvironmentVariable (string $name) : bool {
return isset($_SERVER[$name]) || isset($_SERVER["REDIRECT_${name}"]);
}
Im Idealfall erledigt eine Funktion genau eine Aufgabe.
Was allerdings "genau eine Aufgabe" ist dann wieder eine Frage der Aufgabendefinition...
@@1unitedpower & Regina Schaukrug: Jetzt übertreibt Ihr aber. Wenn ich eine einmalige Abfrage benötige, so werde ich doch keine, auch noch so einfache Funktion schreiben. Gruß Frederic
Hallo Frederic,
nein, das ist nicht übertrieben. Das ist Software-Engineering vs. Adhoc-Programmierung.
So richtig korrekt gehören beide Funktionen als METHODEN in eine ServerEnvironment Adapterklasse, für die Du nach Bedarf unterschiedliche Implementierungen für unterschiedliche Webserver bereitstellen kannst, und deren Instanz Du deinen Arbeitsklassen per Dependency Injection übergibst. Dann kannst Du das alles auch schön unabhängig vom Server unittesten.
Und ob die Sache einmalig ist, weißt Du oftmals erst einige Zeit später. Man muss sich natürlich vor over-engineering hüten.
Rolf
hi @Rolf B
Hallo Frederic,
nein, das ist nicht übertrieben. Das ist Software-Engineering vs. Adhoc-Programmierung.
So richtig korrekt gehören beide Funktionen als METHODEN in eine ServerEnvironment Adapterklasse, für die Du nach Bedarf unterschiedliche Implementierungen für unterschiedliche Webserver bereitstellen kannst, und deren Instanz Du deinen Arbeitsklassen per Dependency Injection übergibst. Dann kannst Du das alles auch schön unabhängig vom Server unittesten.
Und ob die Sache einmalig ist, weißt Du oftmals erst einige Zeit später. Man muss sich natürlich vor over-engineering hüten.
Komplizierter hätte ich das auch nicht ausdrücken können 😉
@@1unitedpower & Regina Schaukrug: Jetzt übertreibt Ihr aber. Wenn ich eine einmalige Abfrage benötige, so werde ich doch keine, auch noch so einfache Funktion schreiben. Gruß Frederic
Doch, wirst Du 😉
Späatestens nachdem Du den Sinn einer API verstanden hast, die Methoden bereitstellt. Der Name einer Methode bleibt nämlich immer derselbe, was heißt daß man nicht den ganzen Code umschreiben muss wenn sich an den Datenquellen was ändert.
MfG
Wenn ich eine einmalige Abfrage benötige, so werde ich doch keine, auch noch so einfache Funktion schreiben.
Mag sein. Aber wir wussten das mit der "Einmaligkeit" nicht. Für mich und sicherlich auch @@1unitedpower bestand die an Gewissheit grenzende Vermutung, dass Du das (oder auch nur "sowas") immer mal wieder brauchen wirst.
Das kommt mir jetzt so vor, als ob Ihr aus allem eine Funktion machen wollt. Mein Problem war eine einzige Abfrage wie if ($a < $b).
Aber Ihr macht daraus eine Funktion
function kleiner($x,$y) {
if ($x < $y) return true
else return false
}
Selbst wenn die Abfrage in mathematischen Zusammenhängen x-mal vorkommt, so steht dort sinnvollerweise immer
if (($a<$B)... and $x < 5.….…
…
if ($x < $y) ...
Dies übrigens schon aus Performance-Gründen.
Lieber Frederic,
Das kommt mir jetzt so vor, als ob Ihr aus allem eine Funktion machen wollt.
das kommt mir jetzt so vor, als wolltest Du uns nicht verstehen.
Mein Problem war eine einzige Abfrage wie if ($a < $b).
Nein. Dein Problem war ein völlig anderes: Wie bekomme ich Werte von außen in mein PHP-Programm? DAS war Dein Problem. Du hast versucht es dadurch zu lösen, indem Du in .htaccess
solche Werte als PHP-Variablen definierst. Dass das auf verschiedenen Systemen nicht so zuverlässig funktioniert, führte Dich zu diesem Thread.
Aber Ihr macht daraus eine Funktion
Nein, wir schreiben eine Funktion, die diese Werte einmalig von einer externen Datenquelle (Config-File) einliest, damit sie im weiteren Programmverlauf dauerhaft zur Verfügung stehen. Man kann die Funktionalität dieser Funktion auch im Hauptteil des Programms notieren - aber das ist absolut nebensächlich.
Was verstehst Du daran nicht?
Liebe Grüße,
Felix Riesterer.
Das kommt mir jetzt so vor, als ob Ihr aus allem eine Funktion machen wollt.
Für meinen Teil liegst du mit deiner Einschätzung völlig richtig. Ich habe einen Faible für funktionale Programmierung.
Dies übrigens schon aus Performance-Gründen.
Damit wirst du keinen messbaren Effekt erzielen. Du kannst ja mal die Probe machen: Zeichne mit xdebug zwei Performance-Profile auf, einmal mit und einmal ohne Funktions-Wrapper. Du wirst sehen, dass das keinen Unterschied macht und mit etwas Glück findest du gleich auch einen echten Engpass, den du weg optimieren kannst.