PHP und Dateien >2GB

theton

theton

Bitmuncher
Kann mir irgendwer erklaeren, wie ich PHP dazu bringe, dass es Dateien mit mehr als 2GB erzeugen kann? Ich versuche einen access_log vom Apache zu parsen (im Laufe von 4 Jahren, haben sich da 3.2GB angesammelt), die Referer-Eintraege zu entfernen und das Ergebnis in eine neue Datei zu schreiben. Sobald die neue Datei 2GB erreicht hat, bekomme ich aber die Meldung "file size limit exceeded".
Es liegt garantiert nicht am Dateisystem, denn auf der gleichen Partition liegt bereits die 3.2GB grosse access_log, diese Fehlerquelle kann man also schonmal ausschliessen. Es muss also irgendwas mit PHP zu tun haben. Muss ich beim Kompilieren irgendeine bestimmte Option fuer configure angeben? Oder muss ich irgendein CFLAG setzen? Bin echt ratlos. :think:
 
Hier der Output von ulimit -a

Code:
core file size        (blocks, -c) 0
data seg size         (kbytes, -d) unlimited
file size             (blocks, -f) unlimited
max locked memory     (kbytes, -l) 32
max memory size       (kbytes, -m) unlimited
open files                    (-n) 1024
pipe size          (512 bytes, -p) 8
stack size            (kbytes, -s) unlimited
cpu time             (seconds, -t) unlimited
max user processes            (-u) 3967
virtual memory        (kbytes, -v) unlimited
 
das ulimit -a hast du auch mit dem user abgesetzt unter dem php läuft?
 
Ja... Ich administriere jetzt seit einigen Jahren Linux- und Unix-Server. :) Hab halt nur bisher wenig mit PHP zu tun gehabt. Es liegt garantiert nicht an irgendwelchen Einschraenkungen des Systems. Habe da schon alles moegliche durchgeschaut (Sicherheitsrichtlinien, Beschraenkungen im Kernel u.ae.). Das Script fuehre ich als root aus. Es wird nicht aus dem Webserver gestartet, von daher sind Limitierungen fuer irgendwelche User keine moegliche Fehlerquelle.
 
Hallo
Passiert dir das nur unter php?
Was passiert, wenn du z.b. mit dd oder perl eine Datei größer 2GB im gleichen F-System erzeugst?
Eventuell ist da ja kein Platz mehr?
Teste das mal aus.

Beim Apache ist mir nur in Erinnerung, dass es in der alten Version mal eine Beschränkung von 2GB beim Download gab.
Aber das hat damit wohl eher nix zu tun.

Gruß Wolfgang
Der mit php nicht so viel am Hut hat!
 
Es hat nix mit Apache zu tun (wie ich bereits erwaehnte, starte ich das Script als root auf der Konsole) und auf der Partition sind noch mehr als 200GB Platz. Auch der verfuegbare RAM kann es nicht sein, der Server hat 4GB davon. Das Problem taucht bei dd nicht auf, denn (auch das schrieb ich bereits) auf der gleichen Partition liegt eine Datei mit 3.2GB (genau die, die ich parsen will).
 
Zuletzt bearbeitet:
diese 3.2 gb datei wurde auch mit root erstellt oder mit einem anderen user? wenns ein anderer war, würd ich schon sagen versuch mal mit root eine datei >2gb anzulegen, wie gesagt dd eignet sich gut dafür
 
Hallo hier ist was ich bei php.net gefunden habe
Code:
If you want to open large files (more than 2GB) 
that's what I did and it works: 
you should recompile your php 
with the CFLAGS="-D_FILE_OFFSET_BITS=64" ./configure etc... 
This tells to your compiler 
(I tested only gcc on PHP-4.3.4 binary on Linux and Solaris) 
to make the PHP parser binary large file aware. 
This way fopen() will not give you the 
"Value too large for defined data type" 
error message.
God bless PHP
ciao
Sergio Paternoster

hier noch der Link dazu
http://de.php.net/fopen()

Fehlermeldung trifft nicht hunderprozentig zu aber eventuell mal ein Ansatz.

Viel Glück
 
Also C müsste eigentlich kein Problem mit 3.2G haben machmal ne mmap in den Memory und perform dann deine regexes. Sollte auch schneller gehen, als PHP.
 
Ist auch nicht mal schwer den C Kram nachher in Apache einzubinden, dass man zum Beispiel was übers Inet auslesen kann.
Wenn Intresse besteht schau ich mal ob ich noch meine alten Experimente mit nem kleinen hallo welt apache plugin finde oder wie das in php mit der pipe zu ausführbaren Programmen ging (hab nur grade keine Lust meinen alten server (200er P1) hochzufahrn ^^).
 
Also das CFLAG beim Kompilieren zu setzen habe ich jetzt mal versucht. Danach hatte aber der Webserver (der ja schliesslich auch das gleiche PHP nutzt) Probleme und gab nur noch leere html-Gerueste zurueck, verarbeitete also PHP-Code offensichtlich nicht mehr richtig bzw. ignoriert jegliches echo() und print().
Den Spass mit C zu parsen ist fuer mich nichtmal ne Ueberlegung wert, denn ich denke, dass C fuer diese Aufgabe total ungeeignet ist. Evtl. will ich das Skript spaeter noch im Apache benutzen, auch wenn das momentan noch nicht geplant ist. Und wer schonmal nen Parser in C geschrieben hat, der weiss, dass das "mit Kanonen auf Spatzen schiessen" waere.
Alle Dateien, mit denen ich gerade arbeite (sowohl die access_log als auch das Skript selbst) habe ich als root angelegt bzw. als root von einem anderen Server gezogen. Ich kann nur nochmal wiederholen, ich bin zu 99,9% sicher, dass es nicht am Dateisystem oder irgendwelche Einschraenkungen durch das OS liegt. Es ist ueberhaupt kein Problem irgendwelche Dateien >2GB anzulegen, egal mit welchem User, habe ich alles schon ueberprueft. Und ich wuerde nicht in diesem Forums-Bereich schreiben, wenn ich nicht davon ausgehen wuerde, dass es am PHP liegt.
Das mit dem CFLAG war ne Hoffnung, aber wenn PHP dann keinen Output mehr produziert (und offenbar jedes print und echo ignoriert) bringt es mich leider nicht weiter. :(
 
theton schrieb:
Also das CFLAG beim Kompilieren zu setzen habe ich jetzt mal versucht. Danach hatte aber der Webserver (der ja schliesslich auch das gleiche PHP nutzt) Probleme und gab nur noch leere html-Gerueste zurueck, verarbeitete also PHP-Code offensichtlich nicht mehr richtig bzw. ignoriert jegliches echo() und print().
Den Spass mit C zu parsen ist fuer mich nichtmal ne Ueberlegung wert, denn ich denke, dass C fuer diese Aufgabe total ungeeignet ist. Evtl. will ich das Skript spaeter noch im Apache benutzen, auch wenn das momentan noch nicht geplant ist. Und wer schonmal nen Parser in C geschrieben hat, der weiss, dass das "mit Kanonen auf Spatzen schiessen" waere.
Alle Dateien, mit denen ich gerade arbeite (sowohl die access_log als auch das Skript selbst) habe ich als root angelegt bzw. als root von einem anderen Server gezogen. Ich kann nur nochmal wiederholen, ich bin zu 99,9% sicher, dass es nicht am Dateisystem oder irgendwelche Einschraenkungen durch das OS liegt. Es ist ueberhaupt kein Problem irgendwelche Dateien >2GB anzulegen, egal mit welchem User, habe ich alles schon ueberprueft. Und ich wuerde nicht in diesem Forums-Bereich schreiben, wenn ich nicht davon ausgehen wuerde, dass es am PHP liegt.
Das mit dem CFLAG war ne Hoffnung, aber wenn PHP dann keinen Output mehr produziert (und offenbar jedes print und echo ignoriert) bringt es mich leider nicht weiter. :(

Ich warte immernoch auf deine php config ... aber anyway ..
 
Wird das PHP Script denn dann noch ausgeführt oder werden nur print und echo ignoriert? Klingt nämlich dannach als wär irgendwas bei der Install vom neu compilierten Php schief gelaufen.
 
Nein, das PHP wird noch ausgefuehrt. Es gibt nur keinen Output zurueck. phpinfo() z.B. gibt ganz normal das uebliche Zeug aus. Nur echo() und print() werden uebergangen, soweit ich das sehe.
 
Hier erstmal die php.ini. Ich habe zwar auch schon geschaut, ob irgendwelche Limits hinsichtlich dem Schreiben von Dateien drin sind, aber wenn du dir davon soviel versprichst... Ich konnte jedenfalls nichts finden:

Code:
[PHP]
engine = On
short_open_tag = On
asp_tags = Off
precision    =  14
y2k_compliance = Off
output_buffering = Off
zlib.output_compression = Off
implicit_flush = Off
unserialize_callback_func=
allow_call_time_pass_reference = On
safe_mode = Off
safe_mode_gid = Off
safe_mode_include_dir =								
safe_mode_exec_dir =
safe_mode_allowed_env_vars = PHP_
safe_mode_protected_env_vars = LD_LIBRARY_PATH
disable_functions =
expose_php = On
max_execution_time = 18000     ; Maximum execution time of each script, in seconds
max_input_time = 60	; Maximum amount of time each script may spend parsing request data
memory_limit = 250M      ; Maximum amount of memory a script may consume (8MB)
error_reporting = E_ALL & ~E_NOTICE
display_errors = On
display_startup_errors = On 
log_errors = Off
log_errors_max_len = 1024
ignore_repeated_errors = Off
ignore_repeated_source = Off
report_memleaks = On
track_errors = Off
variables_order = "EGPCS"
register_globals = On
register_argc_argv = On
post_max_size = 200M
magic_quotes_gpc = On
magic_quotes_runtime = Off    
magic_quotes_sybase = Off
auto_prepend_file =
auto_append_file =
default_mimetype = "text/html"
include_path="/www/htdocs/phpunit"
include_path="/usr/share/php"
doc_root =
user_dir =
extension_dir = ./
extension_dir = /usr/share/extensions/no-debug-non-zts-20020429
enable_dl = On
cgi.force_redirect = 0 
file_uploads = On
upload_max_filesize = 200M
allow_url_fopen = On
default_socket_timeout = 60
[extension section]
[Syslog]
define_syslog_variables  = Off
[mail function]
SMTP = mail.meinefirma.de
sendmail_from = administration@meinefirma.de
[Java]
[SQL]
sql.safe_mode = Off
[ODBC]
odbc.allow_persistent = On
odbc.check_persistent = On
odbc.max_persistent = -1
odbc.max_links = -1  
odbc.defaultlrl = 4096  
odbc.defaultbinmode = 1  
[MySQL]
mysql.allow_persistent = On
mysql.max_persistent = -1
mysql.max_links = -1
mysql.default_port =
mysql.default_socket =
mysql.default_host =
mysql.default_user =
mysql.default_password =
mysql.connect_timeout = -1
mysql.trace_mode = Off
[mSQL]
msql.allow_persistent = On
msql.max_persistent = -1
msql.max_links = -1
[PostgresSQL]
pgsql.allow_persistent = On
pgsql.auto_reset_persistent = Off 
pgsql.max_persistent = -1
pgsql.max_links = -1
pgsql.ignore_notice = 0
pgsql.log_notice = 0
[Sybase]
sybase.allow_persistent = On
sybase.max_persistent = -1
sybase.max_links = -1
sybase.min_error_severity = 10
sybase.min_message_severity = 10
sybase.compatability_mode = Off
[Sybase-CT]
sybct.allow_persistent = On
sybct.max_persistent = -1
sybct.max_links = -1
sybct.min_server_severity = 10
sybct.min_client_severity = 10
[dbx]
dbx.colnames_case = "unchanged"
[bcmath]
bcmath.scale = 0
[browscap]
browscap = /www/htdocs/browscap.ini
[Informix]
ifx.default_host = informixdb1.meinefirma.de
ifx.default_user =
ifx.default_password =
ifx.allow_persistent = On
ifx.max_persistent = -1
ifx.max_links = -1
ifx.textasvarchar = 0
ifx.byteasvarchar = 0
ifx.charasvarchar = 0
ifx.blobinfile = 0
ifx.nullformat = 0
[Session]
session.save_handler = files
session.save_path = /tmp
session.use_cookies = 1
session.name = PHPSESSID
session.auto_start = 0
session.cookie_lifetime = 0
session.cookie_path = /session-cookies/
session.cookie_domain =
session.serialize_handler = php
session.gc_probability = 1
session.gc_dividend    = 100
session.gc_maxlifetime = 60000 
session.bug_compat_42 = 1
session.bug_compat_warn = 1
session.referer_check =
session.entropy_length = 0
session.entropy_file =
session.cache_limiter = nocache
session.cache_expire = 180
session.use_trans_sid = 0
url_rewriter.tags = "a=href,area=href,frame=src,input=src,form=,fieldset="
[MSSQL]
mssql.allow_persistent = On
mssql.max_persistent = -1
mssql.max_links = -1
mssql.min_error_severity = 10
mssql.min_message_severity = 10
mssql.compatability_mode = Off
mssql.secure_connection = Off
[Assertion]
[Ingres II]
ingres.allow_persistent = On
ingres.max_persistent = -1
ingres.max_links = -1
ingres.default_database =
ingres.default_user =
ingres.default_password =
[Verisign Payflow Pro]
pfpro.defaulthost = "test-payflow.verisign.com"
pfpro.defaultport = 443
pfpro.defaulttimeout = 30
[Sockets]
sockets.use_system_read = On
[com]
[Printer]
[mbstring]
mbstring.internal_encoding = UTF-8
[FrontBase]
;fbsql.allow_persistent = On
;fbsql.autocommit = On
;fbsql.default_database = 
;fbsql.default_database_password =
;fbsql.default_host =
;fbsql.default_password =
;fbsql.default_user = "_SYSTEM"
;fbsql.generate_warnings = Off
;fbsql.max_connections = 128
;fbsql.max_links = 128
;fbsql.max_persistent = -1
;fbsql.max_results = 128
;fbsql.batchSize = 1000
[Crack]
[exif]
;exif.encode_unicode = ISO-8859-15
;exif.decode_unicode_motorola = UCS-2BE
;exif.decode_unicode_intel    = UCS-2LE
;exif.encode_jis = 
;exif.decode_jis_motorola = JIS
;exif.decode_jis_intel    = JIS
[Zend]
#zend_optimizer.optimization_level=15
#zend_extension_manager.optimizer=/usr/local/Zend/lib/Optimizer-2.1.0
#zend_extension_manager.optimizer_ts=/usr/local/Zend/lib/Optimizer_TS-2.1.0
#zend_extension=/usr/local/Zend/lib/ZendExtensionManager.so
#zend_extension_ts=/usr/local/Zend/lib/ZendExtensionManager_TS.so

Das Script, das ich benutze, ist wirklich simpel. Es laeuft halt durch verschiedene access_log-Dateien, die durchnummeriert sind. Dabei wird die access_log-Datei mit der Nummer 9 uebergangen. Hier mal der Inhalt:

Code:
<?
for($b=1; $b<=126; $b++) {
	if($b != 9) {
		$i = 0;
		$filename = "/www/logs/access_log$b";
		echo $filename."\n";
		$pointer = fopen($filename, "r");
		if($pointer) {
			while(!feof($pointer)) {
				$pretext = fgets($pointer, 999);
				$atext[$i] = $pretext;
				$i++;
			}
			fclose($pointer);
		}
		// print $atext[0];
		$elements = $i;
		$output = fopen("/www/logs/access_log", "a");
		for($i=0; $i<$elements; $i++) {
			$pieces = explode(" ", $atext[$i]);
//			print $pieces[0]."\n";
//			print $pieces[1]."\n";
			$numpieces = count($pieces);
			for($a=0; $a<$numpieces; $a++){
				if($a == 10){
					if(fwrite($output, " ") == FALSE){
						print "Couldn't open file write3!\n";
					}
				} else {
					fwrite($output, " ");
					fwrite($output, $pieces[$a]);
				}
			}
		}
		fclose($output);
	}
}
?>

Und ja, es ginge sicherlich auch mit einer regexp, aber so find ich das wesentlich uebersichtlicher. (Beanstandet was ihr wollt, ich werde dieses Script nicht grundlegend aendern, wenn die Aenderungen nicht das Schreiben in die $output-Datei betreffen. :D)
Ich hoffe, das hilft weiter, auch wenn ich es nicht so ganz glaube. :)
 
So, hatte jetzt die Nase voll. Hab den Spass jetzt mit C neu geschrieben und funktioniert auch problemlos. Schreibt die Datei anstandslos auch wenn sie mittlerweilse 5.2GB erreicht hat. Hab ich ja gesagt, dass es nicht am System liegt, sondern an PHP.
 
Hallo
Abgesehen davon, ist PHP in der Shell ohnehin nicht so der Renner.
Aber nun gleich noch C dafür ist mti Kanonen auf Spatzen geschossen. (meine persönliche Meinung!)
Eventuell hätte es ja auch perl getan, was genau dafür geschaffen ist.
Das obige Script geht schon fast mit einem (langen) Einzeiler. ;)

Aber jedem was er möchte.
Soll kein Glaubenskrieg werden.

Wär trotzdem interessant gewesen mal zu erfahren, wo nun der Haken liegt.

Gruß Wolfgang
 
Hallo

mal meine meinung zu dem Thema:

ich finde es bekloppt jedes mal die komplette datei durchzulaufen die ja mit der zeit immer größer wird. wieso cached du die ergebnisse nicht zwischen und lässt mal nen logrotate auf die access laufen. dadurch wird diese deutlich kleiner und du hast immernoch die alten ergebnisse.

was meinst du wie zb webalizer das macht. ich finde die herangehensweise echt schrecklich. ich würde es nie zu so großen dateien kommen lassen.

mfg frank
 
Zurück
Oben