allow_call_time_pass_reference und array_multisort
Thoralf Knuth
- php
Guten Abend,
ich wollte nach dem Training bloß fix ein Script hochladen, was auf meiner Testumgebung wunderbar läuft. Mit Strato hab ich nicht gerechnet. Ich stehe hier kurz vor der Explosion.
allow_call_time_pass_reference ist aus. Weder per .htaccess via php_flags noch per ini_set lässt sich diese Einstellung ändern. Ich weiss, dass dieses Vorgehen deprecated ist, aber siehe unten. *g*
Wegen http://bugs.php.net/bug.php?id=12936 muss ich array_multisort das zu sortierende Array by reference übergeben. Funkioniert auch. Nur bekomm ich dann natürlich die passende Warnung:
Warning: Call-time pass-by-reference has been deprecated - argument passed by value; If you would like to pass it by reference, modify the declaration of array_multisort(). If you would like to enable call-time pass-by-reference, you can set allow_call_time_pass_reference to true in your INI file. However, future versions may not support this any longer. in .../include.php on line 78
Mein error_reporting( E_ALL ) hab ich schon rausgenommen. Aber selbst error_reporting( E_ERROR | E_PARSE ) hilft mir nicht.
array_multisort kann ich auch nicht redeclare'n, wozu auch. Es handelt sich um eine Funktion mit variablen Argumenten, der u.a. Konstanten übergeben werden können, die nicht by Reference übernommen werden können.
Was mache ich, außer das ganze *insert lots of schimpfworts here* Script komplett umzubauen?
Dieses Problem schlägt an mehreren Stellen durch, da sind es aber eigene Funktionen, die ich zur Not entsprechend umstellen kann. Auch wenn es Schwachsinn ist, statt Argumente als optional zu deklarieren, diese wegen der by-ref-Technik pflichtig zu machen und dann in der Funktion gegen FALSE oder was-auch-immer zu vergleichen. Aber array_multisort und preg_match brauchen bestimmte Argumente by reference. Google findet mir haufenweise Fragen ohne echte Antworten, das SelfForum nicht viele Threads, die aber allesamt nicht zu meinem Problem passen.
Ich bin (mal wieder) für jede Anregung dankbar.
Gruß, Thoralf
Nachtrag:
Wenn ich in allen, die betreffende Datei per require einbindenden Dateien, error_reporting( E_ERROR | E_PARSE ) an den Anfang stelle, verschwindet die Warnung. Aber das löst das Problem nicht.
Gruß, Thoralf
Hallo,
bitte poste (, oder verweise auf) das Script!
das ganze Script spielt dabei gar keine Rolle, da ich den Fehler ja soweit eingrenzen kann.
/* Sortiert den Kalender */
function fSortiereKalender( &$arrKalender )
{
/* Vorgabe ist aufsteigend nach Datum und anschließend nach Dauer
Sortiert wird im Moment mittels multisort, eventuell ist usort schneller, ist aber derzeit nicht wichtig */
/* Referenz-Spalten rausziehen */
$arrSortierenNachTS = array(); $arrSortierenNachD = array(); /* Die Referenz-Arrays */
foreach( $arrKalender as $k => $v )
{
$arrSortierenNachTS[$k] = $v["timestamp"];
$arrSortierenNachD[$k] = $v["dauer"];
}
/* Sortieren, Kalender MUSS per Referenz uebergeben werden: http://bugs.php.net/bug.php?id=12936 */
array_multisort( &$arrSortierenNachTS, SORT_ASC, SORT_NUMERIC, &$arrSortierenNachD, SORT_ASC, SORT_NUMERIC, &$arrKalender );
} /* function fSortiereKalender( &$arrKalender ) */
Wegen http://bugs.php.net/bug.php?id=12936 MUSS das Array by reference übergeben werden:
It's a side-effect of the implementation. It could be fixed if I forced all arguments to be passed by reference, but that means that you can't specify SORT_* constants directly as arguments..
Die Funktion greift, wenn das Array by value übergeben wird, auf ein (nicht existentes) Array im globalen Namensraum zu.
Gruß, Thoralf
Hallo,
das ganze Script spielt dabei gar keine Rolle, da ich den Fehler ja soweit eingrenzen kann.
jemand, der mitdenkt - um so besser :)
Hier also Dein funktionstüchtig fehlermeldungsfreier Code zugeschnitten auf CGI 4.1.2
function fSortiereKalender( $arrKalender )
{
$arrSortierenNachTS = array(); $arrSortierenNachD = array();
foreach( $arrKalender as $k => $v )
{
$arrSortierenNachTS[$k] = $v["timestamp"];
$arrSortierenNachD[$k] = $v["dauer"];
}
array_multisort( &$arrSortierenNachTS, SORT_ASC, SORT_NUMERIC, &$arrSortierenNachD, SORT_ASC, SORT_NUMERIC, &$arrKalender );
return($arrKalender);
}
Gruß aus Berlin!
eddi
Hallo,
ich fürchte, wir reden aneinander vorbei. *g*
array_multisort( &$arrSortierenNachTS, SORT_ASC, SORT_NUMERIC, &$arrSortierenNachD, SORT_ASC, SORT_NUMERIC, &$arrKalender );
An genau dieser Zeile kommt dann aber die Warnung, dass Call Time By Reference deprecated wäre. ;)
Gruß, Thoralf
Hallo,
ich fürchte, wir reden aneinander vorbei. *g*
ich fürchte, Du redest nicht über die wichtigen Fankten. Soweit mir bekannt ist, setzt Strato PHP als CGI in der Version 4.1.2 ein. Also habe ich extra ein solch uraltes Benär zum testen gebaut. Es kommen keine Meldungen mit exakt meinem Code - und das bei error_reporting=2047
array_multisort( &$arrSortierenNachTS, SORT_ASC, SORT_NUMERIC, &$arrSortierenNachD, SORT_ASC, SORT_NUMERIC, &$arrKalender );
An genau dieser Zeile kommt dann aber die Warnung, dass Call Time By Reference deprecated wäre. ;)
Ist unter diesen Umständen nicht reproduzierbar.
Gruß aus Berlin!
eddi
function fSortiereKalender( $arrKalender )
{
$arrSortierenNachTS = array(); $arrSortierenNachD = array();
foreach( $arrKalender as $k => $v )
{
$arrSortierenNachTS[$k] = $v["timestamp"];
$arrSortierenNachD[$k] = $v["dauer"];
}
array_multisort( $arrSortierenNachTS, SORT_ASC, SORT_NUMERIC, $arrSortierenNachD, SORT_ASC, SORT_NUMERIC, $arrKalender );
return($arrKalender);
}
Mein Fehler! Ich habe Dir den falschen Code gepostet ;(
Aber das funktioniert jetzt - bestimmt und selbst bei strato
Gruß aus Berlin!
eddi
Hallo,
Mein Fehler! Ich habe Dir den falschen Code gepostet ;(
Aber das funktioniert jetzt - bestimmt und selbst bei strato
Yep, das funktioniert, nur dann wird das Array nicht sortiert. ;) Weil er eben auf $_GLOBAL["arrKalender"] zugreift. ;)
Das Problem ist relativ klar:
1. allow_call_time_pass_reference ist bei Strato Off und ich krieg es nicht On
2. array_multisort braucht prinzipbedingt das zu sortierende Array by reference, wenn es aus einer Funktion heraus aufgerufen wird.
3. Beides geht nicht miteinander:
By value bringt natürlich keine Warnung, array_multisort sortiert dann aber nicht das Array, was ich übergebe.
By reference bringt den gewünschten Effekt, aber eben mit Warnung.
Weißt Du, ob man bei Strato ähnlich wie bei 1und1 per "besondere" Einstellung das entsprechende PHP-Flag abstellen kann?
Gruß, Thoralf
Re:
Yep, das funktioniert, nur dann wird das Array nicht sortiert. ;) Weil er eben auf $_GLOBAL["arrKalender"] zugreift. ;)
bei meinen Gegenversuchen wird es sortiert. Desweiteren bin ich gespannt, mit welcher Erklärung Du mir weiß machen willst, daß innerhalb einer Funktion eine globale Variable geändert wird.
Weißt Du, ob man bei Strato ähnlich wie bei 1und1 per "besondere" Einstellung das entsprechende PHP-Flag abstellen kann
HALLO? Sind bei Dir noch wenigstens zwei Graue Zellen aktiv? Wir reden von strato! ;)
Gruß aus Berlin!
eddi
Re:
Noch mehr Rehe:
bei meinen Gegenversuchen wird es sortiert.
Mit entsprechendem Flag auf "Off"? Ich hab das in meinem Account (all-inkl) entsprechend getestet, und da hat er eben auch nicht sortiert.
Desweiteren bin ich gespannt, mit welcher Erklärung Du mir weiß machen willst, daß innerhalb einer Funktion eine globale Variable geändert wird.
http://bugs.php.net/bug.php?id=12936:
Bugreport: When called inside a function array_multisort changes the global
variables instead of the local copy the function should be working
with.
Antwort: It's a side-effect of the implementation. It could be fixed if I forced
all arguments to be passed by reference, but that means that you can't
specify SORT_* constants directly as arguments.
;)
Weißt Du, ob man bei Strato ähnlich wie bei 1und1 per "besondere" Einstellung das entsprechende PHP-Flag abstellen kann
HALLO? Sind bei Dir noch wenigstens zwei Graue Zellen aktiv? Wir reden von strato! ;)
Hier war mein erster Gedanke, ja sag mal, spinnt der denn. Der zweite dann, hm, er wird wohl recht haben. Naja, muss ich doch auf lange Sicht mal anregen, den Provider zu wechseln. ;)
Bis dahin scheint mir aber tatsächlich nichts anderes übrig zu bleiben, als per error_reporting() tatsächlich alle E_WARNINGs zu unterdrücken. Da stellen sich mir die Haare auf.
Gruß, Thoralf
echo $begrüßung;
Ein interessantes Problem hast du dir da eingefangen :-)
allow_call_time_pass_reference ist aus. Weder per .htaccess via php_flags noch per ini_set lässt sich diese Einstellung ändern.
Ich wollte erst fragen, was gegen ein "gutes altes" @ spricht, jedoch bemerkte ich, dass weder dieses noch ein temporär ausgeschaltetes display_errors wirkt. Der Grund ist, dass die Warnung nicht während der Laufzeit sondern schon beim Parsen ausgeworfen wird. Nachvollziehen kann man das, indem man zwar die Funktionsdeklaration von msortWithRef() aus dem Beispiel von
drinlässt, aber deren Aufruf entfernt. Die Warnung kommt auch dann.
Mein error_reporting( E_ALL ) hab ich schon rausgenommen. Aber selbst error_reporting( E_ERROR | E_PARSE ) hilft mir nicht.
Im Script ist das auch zu spät - siehe oben. Wenn
php_flag allow_call_time_pass_reference On
in der .htaccess keine Wirkung zeigt - manche Provider sollen ja einige Werte fest verdrahtet haben, wobei sich mir der Sinn des Feststellens dieses Wertes nicht erschließt, dieses Feature ist schließlich nur veraltet und nicht sicherheitsrelevant - dann bleibt nur das Umstellen des error_reporting- oder des display_error-Wertes in der .htaccess. (error_reporting nimmt in der .htaccess nur Zahlenwerte an, die E_*-Konstanten sind an der Stelle unbekannt).
Das Anzeigen der Fehlermeldungen auszuschalten ist in der Produktivumgebung keine schlechte Idee. Die (regulären) Anwender können sowieso nichts damit anfangen. Besser ist es, sie per error_log oder eigener Errorhandler-Funktion aufzufangen und sie so nur dem administativen Personal zur Verfügung zu stellen.
Ansonsten fällt mir nur ein, eine eigene Implementation dieser Funktionalität zu schreiben.
echo "$verabschiedung $name";
Hallo,
in der .htaccess keine Wirkung zeigt - manche Provider sollen ja einige Werte fest verdrahtet haben, wobei sich mir der Sinn des Feststellens dieses Wertes nicht erschließt, dieses Feature ist schließlich nur veraltet und nicht sicherheitsrelevant - dann bleibt nur das Umstellen des error_reporting- oder des display_error-Wertes in der .htaccess. (error_reporting nimmt in der .htaccess nur Zahlenwerte an, die E_*-Konstanten sind an der Stelle unbekannt).
das ganze wird noch etwas ulkiger mit dem "strato"-Faktor. Denn ich habe sowahl auf meinem kleinen Testgelende erstmal ein altes PHP 4.1.2 gebaut und ausprobiert, als auch auf einem reell unter der Verwaltung von strato stehenden Webspace ausprobiert. Nun sollte man meinen, daß der Übersichtlichkeit und Handhabbarkeit wegen jeder Webspace beim besagten "Provider" einer gleichenden Konfiguration unterliegt - Pustekuchen!
Auf dem Webspace hier ist es möglich verzeichnisweit, sich aus solcher Klemme mit einer eigenen php.ini zu behelfen. Die Grundeinstellung für allow_call_time_pass_reference hier ist (und jetzt kommts) "On"...
Da fällt einem schlichtweg nichts mehr zu ein ^^
Das Anzeigen der Fehlermeldungen auszuschalten ist in der Produktivumgebung keine schlechte Idee. Die (regulären) Anwender können sowieso nichts damit anfangen. Besser ist es, sie per error_log oder eigener Errorhandler-Funktion aufzufangen und sie so nur dem administativen Personal zur Verfügung zu stellen.
@Thoralf: Es ist wirklich keine schlechte Sache, die Fehlermeldungen zu unterdrücken - ganz im Gegenteil :)
Gruß aus Berlin!
eddi
N'Abend,
Ich wollte erst fragen, was gegen ein "gutes altes" @ spricht, jedoch bemerkte ich, dass weder dieses noch ein temporär ausgeschaltetes display_errors wirkt. Der Grund ist, dass die Warnung nicht während der Laufzeit sondern schon beim Parsen ausgeworfen wird. Nachvollziehen kann man das, indem man zwar die Funktionsdeklaration von msortWithRef() aus dem Beispiel von
http://bugs.php.net/bug.php?id=12936
drinlässt, aber deren Aufruf entfernt. Die Warnung kommt auch dann.
DAS war der Knackpunkt. Ich habe nun alle error_reporting( E_ALL ) auskommentiert und nicht nur danach noch runtergeschraubt. Jetzt klappt es ohne Warnung. Offenbar wird beim Parsen bereits eine E_WARNING geworfen, wenn beim Parsen schon ein entsprechendes error_reporting gefunden wird.
in der .htaccess keine Wirkung zeigt - manche Provider sollen ja einige Werte fest verdrahtet haben, wobei sich mir der Sinn des Feststellens dieses Wertes nicht erschließt, dieses Feature ist schließlich nur veraltet und nicht sicherheitsrelevant - dann bleibt nur das Umstellen des error_reporting- oder des display_error-Wertes in der .htaccess. (error_reporting nimmt in der .htaccess nur Zahlenwerte an, die E_*-Konstanten sind an der Stelle unbekannt).
Das war das, wo eddi
HALLO? Sind bei Dir noch wenigstens zwei Graue Zellen aktiv? Wir reden von strato! ;)
rief. *bg*
Das Anzeigen der Fehlermeldungen auszuschalten ist in der Produktivumgebung keine schlechte Idee. Die (regulären) Anwender können sowieso nichts damit anfangen. Besser ist es, sie per error_log oder eigener Errorhandler-Funktion aufzufangen und sie so nur dem administativen Personal zur Verfügung zu stellen.
Hehe, das hab ich bei Strato schon gar nicht mehr probiert. Aber mittlerweile hab ich genau das gemacht, weil (s.o.) trotz Warnung die Referenzierei funktioniert.
Ansonsten fällt mir nur ein, eine eigene Implementation dieser Funktionalität zu schreiben.
Ganz so schlimm wärs nicht geworden, ich hätte die betroffenen Paramter eben als globale Variablen bereithalten müssen. Was passieren würde, wenn ich dieses Problem in einer Methode statt in einer Funktion gehabt hätte, will ich gar nicht wissen. :/
Regengruß, Thoralf
So, nach einiger Probiererei, hab ich die "Lösung" gefunden.
In der Datei, in der by reference übergeben wird, hilft error_reporting ohne E_WARNING nicht. Wenn ich dieselbe Datei aber per require (include nicht mehr probiert) einbinde, und in der aufrufenden Datei entsprechendes error_reporting setze, dann geht es. Strange, aber funktioniert.
1. Alte loeschen.php umbenannt nach loeschen-include.php
2. <?php error_reporting( E_ERROR | E_PARSE ); require( './loeschen-include.php' ); ?>
als loeschen.php funktioniert.
Danke an eddi & dedlfix für die Anregungen!
Gruß, Thoralf