September 2011 Archives
2011-09-19 22:07:58
Call to undefined function gzopen()
Auf 32-Bit-Systemen und aktiviertem Largefilesupport in der Zlib kann es beispielsweise bei Verwendung von PHP zu "Fehlern" kommen. Dieser Fehler erschien bei dem Versuch, Magento auf einem 32-Bit-System mit LFS-Support in Zlib und PHP zu installieren:
Fatal error: Call to undefined function gzopen() in \ /html/install/downloader/lib/Mage/Archive/Gz.php on line 60
Das ist aber anscheinend ein allgemeines Problem und durchaus aktuell, wie dieser Thread zeigt: https://bugs.launchpad.net/ubuntu/+source/php5/+bug/432291
Der Fehler tauchte bei dieser Distro auf, nachdem der Debian-Patch "019-z_off_t_as_long.patch" deaktiviert wurde. Dabei trat dann der Nebeneffekt auf, dass nur noch gzopen64() definiert war. Der Ansatz war ja löblich, den Patch nicht ungeprüft von dieser Distribution zu übernehmen (ya remember "OpenSSL-Debakel" und "16 Bit Entropie"?), doch leider wurde dieser Patch dann doch wieder aktiviert, anscheinend ohne sich über die Hintergründe im Klaren zu sein. Zu dem Patch findet man folgende Infos:
* Add 019-z_off_t_as_long.patch, including local headers for zlib, forcing off_t = long for gzip file functions, however disable it for now, as we'll only need it if we reenable LFS (closes: #208608)
Der Patch bewirkt die Installation von zwei Zlib-Header-Dateien. Dabei wird der Zlib-interne off_t-Typ als "long" definiert. Die Header-Dateien selbst stammen von der Zlib 1.2.1.1 und überschreiben ihre Brüder, die systemweit installiert sind und vermutlich von einer neueren Zlib stammen. So eine Vorgehensweise "unsauber" zu nennen, wäre ein Kompliment, aber zum Thema QM kann nur noch einmal auf OpenSSL und die 16 Bit breite Entropie verwiesen werden.
Doch wie löst man das Problem? Als Maintainer kann man bugs.php.net bemühen oder es über einen Kontakt klären. Für die Homebrew-Variante schauen wir uns mal einen Teil der aktuellen Zlib-Header-Dateien an:
$ grep -B1 -A21 "define gzopen" /usr/include/zlib.h #if !defined(ZLIB_INTERNAL) && _FILE_OFFSET_BITS-0 == 64 && \ _LFS64_LARGEFILE-0 # define gzopen gzopen64 # define gzseek gzseek64 # define gztell gztell64 # define gzoffset gzoffset64 # define adler32_combine adler32_combine64 # define crc32_combine crc32_combine64 # ifdef _LARGEFILE64_SOURCE ZEXTERN gzFile ZEXPORT gzopen64 OF((const char *, const \ char *)); ZEXTERN z_off_t ZEXPORT gzseek64 OF((gzFile, z_off_t, \ int)); ZEXTERN z_off_t ZEXPORT gztell64 OF((gzFile)); ZEXTERN z_off_t ZEXPORT gzoffset64 OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine64 OF((uLong, uLong, \ z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine64 OF((uLong, uLong, \ z_off_t)); # endif #else ZEXTERN gzFile ZEXPORT gzopen OF((const char *, const char \ *)); ZEXTERN z_off_t ZEXPORT gzseek OF((gzFile, z_off_t, int)); ZEXTERN z_off_t ZEXPORT gztell OF((gzFile)); ZEXTERN z_off_t ZEXPORT gzoffset OF((gzFile)); ZEXTERN uLong ZEXPORT adler32_combine OF((uLong, uLong, \ z_off_t)); ZEXTERN uLong ZEXPORT crc32_combine OF((uLong, uLong, \ z_off_t)); #endif
Da wir die Zlib intern in PHP nutzen wollen und dabei auf keinen Fall gzopen64(), sondern statt dessen gzopen() haben wollen, definieren wir zum Übersetzen von PHP ganz einfach ZLIB_INTERNAL, beispielsweise mit der gcc-Option "-DZLIB_INTERNAL=1". Wenn man das an die CFLAGS anhängt, bevor man ./configure aufruft, dann wird PHP damit übersetzt und beim Include der Zlib-Header-Dateien werden die "internen" Namen gzopen() etc. deklariert.