From jorton at redhat.com Tue Jul 14 15:46:21 2009 From: jorton at redhat.com (Joe Orton) Date: Tue, 14 Jul 2009 16:46:21 +0100 Subject: [Fedora-php-devel-list] [jorton@redhat.com: Re: [php-maint] Bug#535770: PHP system timezone patch for 5.3?] Message-ID: <20090714154621.GA2945@redhat.com> Looks like I failed to CC that as intended, copying for the archives. ----- Forwarded message from Joe Orton ----- From: Joe Orton To: sean finney Cc: PHP Packagers , 535770 at bugs.debian.org, judas.iscariote at gmail.com Date: Tue, 7 Jul 2009 10:10:06 +0100 Subject: Re: [php-maint] Bug#535770: PHP system timezone patch for 5.3? User-Agent: Mutt/1.5.18 (2008-05-17) Hi Sean - adding the Fedora PHP devel list to CC. Thanks for getting in touch. For Fedora folks, Sean has referenced this Debian bug report: http://bugs.debian.org/cgi-bin/bugreport.cgi?bug=535770 Quoting in full: On Tue, Jul 07, 2009 at 12:05:31AM +0200, sean finney wrote: > ...and hi again :) > > On Mon, Jul 06, 2009 at 10:51:40PM +0200, sean finney wrote: > > specifically timezone_identifiers_list() was extended to include country > > codes as a filter for the returned values and it doesn't look like this > > is covered by the patch and results in a segfault. > > looking a bit more at the specifics, it doesn't seem so desirable to have > to mmap and read every file to get all the country codes. here's some > options i see: > > - read all the files anyway. performance will be dismal but it's hopefully > a corner case except for someone running a public world clock app or > something :) > > - fall back to the internal timezonedb for listing country names. it would > be a bit ugly and there's maybe a possibility that timezone names might > get out of sync. > > - pre-cache the tzdata at install time (and make use of triggers to > catch updates to the tzdata files). nice performance but adds extra > complexity/dependencies outside of the engine. > > - use zone.tab for country code -> tzdata mapping? it seems to have the > info we'd want all in one file (assuming it's correct and consistant), > and we'd only have to read it in the specific cases that it was needed. > > - disable the api extension. not desirable. > > i guess zone.tab seems a nice easy and boring fix for this, what do you think? It looks like they are (as threatened) shipping a mutated version of the zoneinfo data in 5.3. Changes: 1) first four bytes are "PHP1" not "TZif" 2) in the "reserved" 16 bytes which follow, they have: ONE BYTE: "BC" flag TWO BYTES: country code ... those are being used by the code you mention above 3) after the end of the data, they have: TWO BYTES: latitude and longtitude ONE BYTE: length N (N) BYTES: "comment" Whereas we have the 64-bit TZif2 block at the end of the TZif data. I think that's everything that's different. The "BC" flag seems to be an indication that the zone name is a deprecated form, and it's the case that BC is 0 if and only if the country code is '??', otherwise BC is 1; with 'UTC' as a special-case (BC=1, code is '??'). I believe it is also the case that, other than UTC, there is a one-to-one mapping between zones *not* listed in zone.tab, and zones which PHP designates with country code '??' (and hence BC=0). zone.tab also has the lat/long data, and the country codes, so, yup, parsing that at startup seems to be the way to go. I'll have a crack at a patch later today hopefully. Regards, Joe ----- End forwarded message ----- From jorton at redhat.com Tue Jul 14 15:53:40 2009 From: jorton at redhat.com (Joe Orton) Date: Tue, 14 Jul 2009 16:53:40 +0100 Subject: [Fedora-php-devel-list] Re: [php-maint] Bug#535770: PHP system timezone patch for 5.3? In-Reply-To: <20090707091006.GA4312@redhat.com> References: <20090706205140.GA16626@rangda.stickybit.se> <20090706220531.GA24974@rangda.stickybit.se> <20090707091006.GA4312@redhat.com> Message-ID: <20090714155340.GB2945@redhat.com> Hi folks, I've attached "v5" of the system timezone patch, which is updated for 5.3.0. This contains the changes to parse zone.tab which I proposed in my previous mail, and should fix the crash reported in the Debian bug 535770. It seems to work fine though I have not tested it exhaustively. Further review and testing would be very welcome! Regards, Joe -------------- next part -------------- Add support for use of the system timezone database, rather than embedding a copy. Discussed upstream but was not desired. History: r5: reverts addition of "System/Localtime" fake tzname. updated for 5.3.0, parses zone.tab to pick up mapping between timezone name, country code and long/lat coords r4: added "System/Localtime" tzname which uses /etc/localtime r3: fix a crash if /usr/share/zoneinfo doesn't exist (Raphael Geissert) r2: add filesystem trawl to set up name alias index r1: initial revision --- php-5.3.0/ext/date/lib/parse_tz.c.systzdata +++ php-5.3.0/ext/date/lib/parse_tz.c @@ -20,6 +20,16 @@ #include "timelib.h" +#ifdef HAVE_SYSTEM_TZDATA +#include +#include +#include +#include +#include + +#include "php_scandir.h" +#endif + #include #ifdef HAVE_LOCALE_H @@ -31,7 +41,12 @@ #else #include #endif + +#ifndef HAVE_SYSTEM_TZDATA #include "timezonedb.h" +#endif + +#include #if (defined(__APPLE__) || defined(__APPLE_CC__)) && (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__)) # if defined(__LITTLE_ENDIAN__) @@ -253,6 +268,427 @@ void timelib_dump_tzinfo(timelib_tzinfo } } +#ifdef HAVE_SYSTEM_TZDATA + +#ifdef HAVE_SYSTEM_TZDATA_PREFIX +#define ZONEINFO_PREFIX HAVE_SYSTEM_TZDATA_PREFIX +#else +#define ZONEINFO_PREFIX "/usr/share/zoneinfo" +#endif + +/* System timezone database pointer. */ +static const timelib_tzdb *timezonedb_system = NULL; + +/* Hash table entry for the cache of the zone.tab mapping table. */ +struct location_info { + char code[2]; + double latitude, longitude; + char name[64]; + char *comment; + struct location_info *next; +}; + +/* Cache of zone.tab. */ +static struct location_info **system_zone_info; + +/* Size of the zone.tab hash table; a random-ish prime big enough to + * prevent too many collisions. */ +#define LOCINFO_HASH_SIZE (1021) + +static uint32_t tz_hash(const char *str) +{ + const unsigned char *p = (const unsigned char *)str; + uint32_t hash = 5381; + int c; + + while ((c = *p++) != '\0') { + hash = (hash << 5) ^ hash ^ c; + } + + return hash % LOCINFO_HASH_SIZE; +} + +/* Parse an ISO-6709 date as used in zone.tab. Returns end of the + * parsed string on success, or NULL on parse error. On success, + * writes the parsed number to *result. */ +static char *parse_iso6709(char *p, double *result) +{ + double v, sign; + char *pend; + size_t len; + + if (*p == '+') + sign = 1.0; + else if (*p == '-') + sign = -1.0; + else + return NULL; + + p++; + for (pend = p; *pend >= '0' && *pend <= '9'; pend++) + ;; + + /* Annoying encoding used by zone.tab has no decimal point, so use + * the length to determine the format: + * + * 4 = DDMM + * 5 = DDDMM + * 6 = DDMMSS + * 7 = DDDMMSS + */ + len = pend - p; + if (len < 4 || len > 7) { + return NULL; + } + + /* p => [D]DD */ + v = (p[0] - '0') * 10.0 + (p[1] - '0'); + p += 2; + if (len == 5 || len == 7) + v = v * 10.0 + (*p++ - '0'); + /* p => MM[SS] */ + v += (10.0 * (p[0] - '0') + + p[1] - '0') / 60.0; + p += 2; + /* p => [SS] */ + if (len > 5) { + v += (10.0 * (p[0] - '0') + + p[1] - '0') / 3600.0; + p += 2; + } + + /* Round to 3 decimal places. */ + *result = round(v * sign * 1000.00)/1000.00; + + return p; +} + +/* This function parses the zone.tab file to build up the mapping of + * timezone to country code and geographic location, and returns a + * hash table. The hash table is indexed by the function: + * + * tz_hash(timezone-name) + */ +static struct location_info **load_zone_table(void) +{ + struct location_info **li, *i; + char zone_tab[PATH_MAX]; + char line[512]; + FILE *fp; + + strncpy(zone_tab, ZONEINFO_PREFIX "/zone.tab", sizeof zone_tab); + + fp = fopen(zone_tab, "r"); + if (!fp) { + return NULL; + } + + li = calloc(LOCINFO_HASH_SIZE, sizeof *li); + + while (fgets(line, sizeof line, fp)) { + char *p = line, *code, *name, *comment; + uint32_t hash; + double latitude, longitude; + + while (isspace(*p)) + p++; + + if (*p == '#' || *p == '\0' || *p == '\n') + continue; + + if (!isalpha(p[0]) || !isalpha(p[1]) || p[2] != '\t') + continue; + + /* code => AA */ + code = p; + p[2] = 0; + p += 3; + + /* coords => [+-][D]DDMM[SS][+-][D]DDMM[SS] */ + p = parse_iso6709(p, &latitude); + if (!p) { + continue; + } + p = parse_iso6709(p, &longitude); + if (!p) { + continue; + } + + if (!p || *p != '\t') { + continue; + } + + /* name = string */ + name = ++p; + while (*p != '\t' && *p && *p != '\n') + p++; + + *p++ = '\0'; + + /* comment = string */ + comment = p; + while (*p != '\t' && *p && *p != '\n') + p++; + + if (*p == '\n' || *p == '\t') + *p = '\0'; + + hash = tz_hash(name); + i = malloc(sizeof *i); + memcpy(i->code, code, 2); + strncpy(i->name, name, sizeof i->name); + i->comment = strdup(comment); + i->longitude = longitude; + i->latitude = latitude; + i->next = li[hash]; + li[hash] = i; + /* printf("%s [%u, %f, %f]\n", name, hash, longitude, latitude); */ + } + + return li; +} + +/* Return location info from hash table, using given timezone name. + * Returns NULL if the name could not be found. */ +const struct location_info *find_zone_info(struct location_info **li, + const char *name) +{ + uint32_t hash = tz_hash(name); + const struct location_info *l; + + if (!li) { + return NULL; + } + + for (l = li[hash]; l; l = l->next) { + if (strcasecmp(l->name, name) == 0) + return l; + } + + return NULL; +} + +/* Since 5.3, php_date.c:timezone_identifiers_list() peeks directly + * into the data array at position + 4, which is the BC flag, so, we + * need to fake one up. For each timezone entry, the 'pos' entry will + * be set to either 0 or 1. pos + 4 will hence be either \1 or \0, + * respectively. Somewhat gross, but means we can avoid patching + * php_date.c. */ +static const unsigned char system_fake_data[] = "1234\1\0"; +#define SYSTEM_FAKE_BC_POS (0) +#define SYSTEM_FAKE_NONBC_POS (1) + +/* Filter out some non-tzdata files and the posix/right databases, if + * present. */ +static int index_filter(const struct dirent *ent) +{ + return strcmp(ent->d_name, ".") != 0 + && strcmp(ent->d_name, "..") != 0 + && strcmp(ent->d_name, "posix") != 0 + && strcmp(ent->d_name, "posixrules") != 0 + && strcmp(ent->d_name, "right") != 0 + && strstr(ent->d_name, ".tab") == NULL; +} + +/* Create the zone identifier index by trawling the filesystem. */ +static void create_zone_index(timelib_tzdb *db) +{ + size_t dirstack_size, dirstack_top; + size_t index_size, index_next; + timelib_tzdb_index_entry *db_index; + char **dirstack; + + /* LIFO stack to hold directory entries to scan; each slot is a + * directory name relative to the zoneinfo prefix. */ + dirstack_size = 32; + dirstack = malloc(dirstack_size * sizeof *dirstack); + dirstack_top = 1; + dirstack[0] = strdup(""); + + /* Index array. */ + index_size = 64; + db_index = malloc(index_size * sizeof *db_index); + index_next = 0; + + do { + struct dirent **ents; + char name[PATH_MAX], *top; + int count; + + /* Pop the top stack entry, and iterate through its contents. */ + top = dirstack[--dirstack_top]; + snprintf(name, sizeof name, ZONEINFO_PREFIX "/%s", top); + + count = php_scandir(name, &ents, index_filter, php_alphasort); + + while (count > 0) { + struct stat st; + const char *leaf = ents[count - 1]->d_name; + + snprintf(name, sizeof name, ZONEINFO_PREFIX "/%s/%s", + top, leaf); + + if (strlen(name) && stat(name, &st) == 0) { + /* Name, relative to the zoneinfo prefix. */ + const char *root = top; + + if (root[0] == '/') root++; + + snprintf(name, sizeof name, "%s%s%s", root, + *root ? "/": "", leaf); + + if (S_ISDIR(st.st_mode)) { + if (dirstack_top == dirstack_size) { + dirstack_size *= 2; + dirstack = realloc(dirstack, + dirstack_size * sizeof *dirstack); + } + dirstack[dirstack_top++] = strdup(name); + } + else { + const struct location_info *li; + + if (index_next == index_size) { + index_size *= 2; + db_index = realloc(db_index, + index_size * sizeof *db_index); + } + + db_index[index_next].id = strdup(name); + + /* Look up the timezone in the zone.tab cache, and see + * whether this is a "BC" name or not; fake the pos + * pointer appropriately. */ + li = find_zone_info(system_zone_info, name); + if (li) { + db_index[index_next].pos = SYSTEM_FAKE_NONBC_POS; + } + else { + db_index[index_next].pos = SYSTEM_FAKE_BC_POS; + } + + index_next++; + } + } + + free(ents[--count]); + } + + if (count != -1) free(ents); + free(top); + } while (dirstack_top); + + db->index = db_index; + db->index_size = index_next; + db->data = system_fake_data; + + free(dirstack); +} + +/* Return the mmap()ed tzfile if found, else NULL. On success, the + * length of the mapped data is placed in *length. */ +static char *map_tzfile(const char *timezone, size_t *length) +{ + char fname[PATH_MAX]; + struct stat st; + char *p; + int fd; + + if (strstr(timezone, "..") != NULL) { + return NULL; + } + + snprintf(fname, sizeof fname, ZONEINFO_PREFIX "/%s", timezone); + + fd = open(fname, O_RDONLY); + if (fd == -1) { + return NULL; + } else if (fstat(fd, &st) != 0 || st.st_size < 21) { + close(fd); + return NULL; + } + + *length = st.st_size; + p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + close(fd); + + return p != MAP_FAILED ? p : NULL; +} + +const timelib_tzdb *timelib_builtin_db(void) +{ + if (timezonedb_system == NULL) { + timelib_tzdb *tmp = malloc(sizeof *tmp); + + tmp->version = "0.system"; + tmp->data = NULL; + create_zone_index(tmp); + system_zone_info = load_zone_table(); + timezonedb_system = tmp; + } + + return timezonedb_system; +} + +const timelib_tzdb_index_entry *timelib_timezone_builtin_identifiers_list(int *count) +{ + *count = timezonedb_system->index_size; + return timezonedb_system->index; +} + +int timelib_timezone_id_is_valid(char *timezone, const timelib_tzdb *tzdb) +{ + char fname[PATH_MAX]; + + if (strstr(timezone, "..") != NULL) { + return 0; + } + + snprintf(fname, sizeof fname, ZONEINFO_PREFIX "/%s", timezone); + + return access(fname, R_OK) == 0 ? 1 : 0; +} + +timelib_tzinfo *timelib_parse_tzfile(char *timezone, const timelib_tzdb *tzdb) +{ + char *orig; + const unsigned char *tzf; + timelib_tzinfo *tmp; + size_t len; + const struct location_info *li; + + orig = map_tzfile(timezone, &len); + if (orig == NULL) { + return NULL; + } + + tmp = timelib_tzinfo_ctor(timezone); + + tzf = (const unsigned char *)orig + 20; + read_header(&tzf, tmp); + read_transistions(&tzf, tmp); + read_types(&tzf, tmp); + + if ((li = find_zone_info(system_zone_info, timezone)) != NULL) { + tmp->location.comments = strdup(li->comment); + strncpy(tmp->location.country_code, li->code, 2); + tmp->location.longitude = li->longitude; + tmp->location.latitude = li->latitude; + tmp->bc = 1; + } + else { + strcpy(tmp->location.country_code, "??"); + tmp->bc = 0; + tmp->location.comments = strdup(""); + } + + munmap(orig, len); + + return tmp; +} + +#else /* !HAVE_SYSTEM_TZDATA */ + static int seek_to_tz_position(const unsigned char **tzf, char *timezone, const timelib_tzdb *tzdb) { int left = 0, right = tzdb->index_size - 1; @@ -328,6 +764,7 @@ timelib_tzinfo *timelib_parse_tzfile(cha return tmp; } +#endif static ttinfo* fetch_timezone_offset(timelib_tzinfo *tz, timelib_sll ts, timelib_sll *transition_time) { --- php-5.3.0/ext/date/lib/timelib.m4.systzdata +++ php-5.3.0/ext/date/lib/timelib.m4 @@ -78,3 +78,17 @@ stdlib.h dnl Check for strtoll, atoll AC_CHECK_FUNCS(strtoll atoll strftime) + +PHP_ARG_WITH(system-tzdata, for use of system timezone data, +[ --with-system-tzdata[=DIR] to specify use of system timezone data], +no, no) + +if test "$PHP_SYSTEM_TZDATA" != "no"; then + AC_DEFINE(HAVE_SYSTEM_TZDATA, 1, [Define if system timezone data is used]) + + if test "$PHP_SYSTEM_TZDATA" != "yes"; then + AC_DEFINE_UNQUOTED(HAVE_SYSTEM_TZDATA_PREFIX, "$PHP_SYSTEM_TZDATA", + [Define for location of system timezone data]) + fi +fi + From Fedora at FamilleCollet.com Tue Jul 14 16:38:22 2009 From: Fedora at FamilleCollet.com (Remi Collet) Date: Tue, 14 Jul 2009 18:38:22 +0200 Subject: [Fedora-php-devel-list] For FPC : Change proposal to PHP Guidelines Message-ID: <4A5CB47E.2040602@FamilleCollet.com> Hi, We have some pending minor issues/questions with PHP packaging we should make clearer : 1/ use of /usr/share/php => 1 folder per library 2/ conditional in ABI check and in post/postun scriplet This conditions are present to maintain compatibility with older PHP version (5.1.6 on EL-5) and could be removed if package requires a recent version (> 5.2) 3/ ABI check With the update of PHP 5.3.0 in rawhide, I discover that a lot of C extensions doesn't use ABI check, Guidelines set is mandatory for PECL extension. Package could be installed, but extension couldn't be load, with the standard PHP error : Module compiled with module API=20060613 PHP compiled with module API=20090626 It seems clear it should be mandatory for all C extension. See bugs : cups https://bugzilla.redhat.com/show_bug.cgi?id=511106 ice https://bugzilla.redhat.com/show_bug.cgi?id=511068 graphviz https://bugzilla.redhat.com/show_bug.cgi?id=511092 uuid https://bugzilla.redhat.com/show_bug.cgi?id=511115 Please review my change proposal https://fedoraproject.org/wiki/PackagingDrafts/PHP Remi From chris.stone at gmail.com Wed Jul 15 14:31:32 2009 From: chris.stone at gmail.com (Christopher Stone) Date: Wed, 15 Jul 2009 07:31:32 -0700 Subject: [Fedora-php-devel-list] Naming Scheme Message-ID: I've seen a couple php-pear packages come through the review pipes recently with underscores in their names like php-pear-HTML_Javascript[1] and php-pear-Auth_HTTP[2]. Shouldn't these have dashes instead of underscores in their names? I thought the naming guidelines suggested not using underscores? Have the rules changed? Regards, Chris [1] https://bugzilla.redhat.com/show_bug.cgi?id=508075 [2] https://bugzilla.redhat.com/show_bug.cgi?id=508082 From jorton at redhat.com Wed Jul 15 16:23:59 2009 From: jorton at redhat.com (Joe Orton) Date: Wed, 15 Jul 2009 17:23:59 +0100 Subject: [Fedora-php-devel-list] Re: [php-maint] Bug#535770: PHP system timezone patch for 5.3? In-Reply-To: <20090714155340.GB2945@redhat.com> References: <20090706205140.GA16626@rangda.stickybit.se> <20090706220531.GA24974@rangda.stickybit.se> <20090707091006.GA4312@redhat.com> <20090714155340.GB2945@redhat.com> Message-ID: <20090715162359.GA30226@redhat.com> v6 attached, which now passes all the tests in the ext/date testsuite and fixes some significant bugs in v5 and earlier. Regards, Joe -------------- next part -------------- Add support for use of the system timezone database, rather than embedding a copy. Discussed upstream but was not desired. History: r6: fix fd leak in r5, fix country code/BC flag use in timezone_identifiers_list() using system db, fix use of PECL timezonedb to override system db, r5: reverts addition of "System/Localtime" fake tzname. updated for 5.3.0, parses zone.tab to pick up mapping between timezone name, country code and long/lat coords r4: added "System/Localtime" tzname which uses /etc/localtime r3: fix a crash if /usr/share/zoneinfo doesn't exist (Raphael Geissert) r2: add filesystem trawl to set up name alias index r1: initial revision Index: ext/date/lib/timelib.m4 =================================================================== --- ext/date/lib/timelib.m4 (revision 284069) +++ ext/date/lib/timelib.m4 (working copy) @@ -78,3 +78,17 @@ dnl Check for strtoll, atoll AC_CHECK_FUNCS(strtoll atoll strftime) + +PHP_ARG_WITH(system-tzdata, for use of system timezone data, +[ --with-system-tzdata[=DIR] to specify use of system timezone data], +no, no) + +if test "$PHP_SYSTEM_TZDATA" != "no"; then + AC_DEFINE(HAVE_SYSTEM_TZDATA, 1, [Define if system timezone data is used]) + + if test "$PHP_SYSTEM_TZDATA" != "yes"; then + AC_DEFINE_UNQUOTED(HAVE_SYSTEM_TZDATA_PREFIX, "$PHP_SYSTEM_TZDATA", + [Define for location of system timezone data]) + fi +fi + Index: ext/date/lib/parse_tz.c =================================================================== --- ext/date/lib/parse_tz.c (revision 284069) +++ ext/date/lib/parse_tz.c (working copy) @@ -20,6 +20,16 @@ #include "timelib.h" +#ifdef HAVE_SYSTEM_TZDATA +#include +#include +#include +#include +#include + +#include "php_scandir.h" +#endif + #include #ifdef HAVE_LOCALE_H @@ -31,8 +41,13 @@ #else #include #endif + +#ifndef HAVE_SYSTEM_TZDATA #include "timezonedb.h" +#endif +#include + #if (defined(__APPLE__) || defined(__APPLE_CC__)) && (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__)) # if defined(__LITTLE_ENDIAN__) # undef WORDS_BIGENDIAN @@ -51,9 +66,14 @@ static void read_preamble(const unsigned char **tzf, timelib_tzinfo *tz) { - /* skip ID */ - *tzf += 4; - + if (memcmp(tzf, "TZif", 4) == 0) { + *tzf += 20; + return; + } + + /* skip ID */ + *tzf += 4; + /* read BC flag */ tz->bc = (**tzf == '\1'); *tzf += 1; @@ -253,8 +273,391 @@ } } -static int seek_to_tz_position(const unsigned char **tzf, char *timezone, const timelib_tzdb *tzdb) +#ifdef HAVE_SYSTEM_TZDATA + +#ifdef HAVE_SYSTEM_TZDATA_PREFIX +#define ZONEINFO_PREFIX HAVE_SYSTEM_TZDATA_PREFIX +#else +#define ZONEINFO_PREFIX "/usr/share/zoneinfo" +#endif + +/* System timezone database pointer. */ +static const timelib_tzdb *timezonedb_system = NULL; + +/* Hash table entry for the cache of the zone.tab mapping table. */ +struct location_info { + char code[2]; + double latitude, longitude; + char name[64]; + char *comment; + struct location_info *next; +}; + +/* Cache of zone.tab. */ +static struct location_info **system_location_table; + +/* Size of the zone.tab hash table; a random-ish prime big enough to + * prevent too many collisions. */ +#define LOCINFO_HASH_SIZE (1021) + +static uint32_t tz_hash(const char *str) { + const unsigned char *p = (const unsigned char *)str; + uint32_t hash = 5381; + int c; + + while ((c = *p++) != '\0') { + hash = (hash << 5) ^ hash ^ c; + } + + return hash % LOCINFO_HASH_SIZE; +} + +/* Parse an ISO-6709 date as used in zone.tab. Returns end of the + * parsed string on success, or NULL on parse error. On success, + * writes the parsed number to *result. */ +static char *parse_iso6709(char *p, double *result) +{ + double v, sign; + char *pend; + size_t len; + + if (*p == '+') + sign = 1.0; + else if (*p == '-') + sign = -1.0; + else + return NULL; + + p++; + for (pend = p; *pend >= '0' && *pend <= '9'; pend++) + ;; + + /* Annoying encoding used by zone.tab has no decimal point, so use + * the length to determine the format: + * + * 4 = DDMM + * 5 = DDDMM + * 6 = DDMMSS + * 7 = DDDMMSS + */ + len = pend - p; + if (len < 4 || len > 7) { + return NULL; + } + + /* p => [D]DD */ + v = (p[0] - '0') * 10.0 + (p[1] - '0'); + p += 2; + if (len == 5 || len == 7) + v = v * 10.0 + (*p++ - '0'); + /* p => MM[SS] */ + v += (10.0 * (p[0] - '0') + + p[1] - '0') / 60.0; + p += 2; + /* p => [SS] */ + if (len > 5) { + v += (10.0 * (p[0] - '0') + + p[1] - '0') / 3600.0; + p += 2; + } + + /* Round to five decimal place, not because it's a good idea, + * but, because the builtin data uses rounded data, so, match + * that. */ + *result = round(v * sign * 100000.0) / 100000.0; + + return p; +} + +/* This function parses the zone.tab file to build up the mapping of + * timezone to country code and geographic location, and returns a + * hash table. The hash table is indexed by the function: + * + * tz_hash(timezone-name) + */ +static struct location_info **create_location_table(void) +{ + struct location_info **li, *i; + char zone_tab[PATH_MAX]; + char line[512]; + FILE *fp; + + strncpy(zone_tab, ZONEINFO_PREFIX "/zone.tab", sizeof zone_tab); + + fp = fopen(zone_tab, "r"); + if (!fp) { + return NULL; + } + + li = calloc(LOCINFO_HASH_SIZE, sizeof *li); + + while (fgets(line, sizeof line, fp)) { + char *p = line, *code, *name, *comment; + uint32_t hash; + double latitude, longitude; + + while (isspace(*p)) + p++; + + if (*p == '#' || *p == '\0' || *p == '\n') + continue; + + if (!isalpha(p[0]) || !isalpha(p[1]) || p[2] != '\t') + continue; + + /* code => AA */ + code = p; + p[2] = 0; + p += 3; + + /* coords => [+-][D]DDMM[SS][+-][D]DDMM[SS] */ + p = parse_iso6709(p, &latitude); + if (!p) { + continue; + } + p = parse_iso6709(p, &longitude); + if (!p) { + continue; + } + + if (!p || *p != '\t') { + continue; + } + + /* name = string */ + name = ++p; + while (*p != '\t' && *p && *p != '\n') + p++; + + *p++ = '\0'; + + /* comment = string */ + comment = p; + while (*p != '\t' && *p && *p != '\n') + p++; + + if (*p == '\n' || *p == '\t') + *p = '\0'; + + hash = tz_hash(name); + i = malloc(sizeof *i); + memcpy(i->code, code, 2); + strncpy(i->name, name, sizeof i->name); + i->comment = strdup(comment); + i->longitude = longitude; + i->latitude = latitude; + i->next = li[hash]; + li[hash] = i; + /* printf("%s [%u, %f, %f]\n", name, hash, latitude, longitude); */ + } + + fclose(fp); + + return li; +} + +/* Return location info from hash table, using given timezone name. + * Returns NULL if the name could not be found. */ +const struct location_info *find_zone_info(struct location_info **li, + const char *name) +{ + uint32_t hash = tz_hash(name); + const struct location_info *l; + + if (!li) { + return NULL; + } + + for (l = li[hash]; l; l = l->next) { + if (strcasecmp(l->name, name) == 0) + return l; + } + + return NULL; +} + +/* Filter out some non-tzdata files and the posix/right databases, if + * present. */ +static int index_filter(const struct dirent *ent) +{ + return strcmp(ent->d_name, ".") != 0 + && strcmp(ent->d_name, "..") != 0 + && strcmp(ent->d_name, "posix") != 0 + && strcmp(ent->d_name, "posixrules") != 0 + && strcmp(ent->d_name, "right") != 0 + && strstr(ent->d_name, ".tab") == NULL; +} + +static int sysdbcmp(const void *first, const void *second) +{ + const timelib_tzdb_index_entry *alpha = first, *beta = second; + + return strcmp(alpha->id, beta->id); +} + + +/* Create the zone identifier index by trawling the filesystem. */ +static void create_zone_index(timelib_tzdb *db) +{ + size_t dirstack_size, dirstack_top; + size_t index_size, index_next; + timelib_tzdb_index_entry *db_index; + char **dirstack; + + /* LIFO stack to hold directory entries to scan; each slot is a + * directory name relative to the zoneinfo prefix. */ + dirstack_size = 32; + dirstack = malloc(dirstack_size * sizeof *dirstack); + dirstack_top = 1; + dirstack[0] = strdup(""); + + /* Index array. */ + index_size = 64; + db_index = malloc(index_size * sizeof *db_index); + index_next = 0; + + do { + struct dirent **ents; + char name[PATH_MAX], *top; + int count; + + /* Pop the top stack entry, and iterate through its contents. */ + top = dirstack[--dirstack_top]; + snprintf(name, sizeof name, ZONEINFO_PREFIX "/%s", top); + + count = php_scandir(name, &ents, index_filter, php_alphasort); + + while (count > 0) { + struct stat st; + const char *leaf = ents[count - 1]->d_name; + + snprintf(name, sizeof name, ZONEINFO_PREFIX "/%s/%s", + top, leaf); + + if (strlen(name) && stat(name, &st) == 0) { + /* Name, relative to the zoneinfo prefix. */ + const char *root = top; + + if (root[0] == '/') root++; + + snprintf(name, sizeof name, "%s%s%s", root, + *root ? "/": "", leaf); + + if (S_ISDIR(st.st_mode)) { + if (dirstack_top == dirstack_size) { + dirstack_size *= 2; + dirstack = realloc(dirstack, + dirstack_size * sizeof *dirstack); + } + dirstack[dirstack_top++] = strdup(name); + } + else { + if (index_next == index_size) { + index_size *= 2; + db_index = realloc(db_index, + index_size * sizeof *db_index); + } + + db_index[index_next++].id = strdup(name); + } + } + + free(ents[--count]); + } + + if (count != -1) free(ents); + free(top); + } while (dirstack_top); + + qsort(db_index, index_next, sizeof *db_index, sysdbcmp); + + db->index = db_index; + db->index_size = index_next; + + free(dirstack); +} + +#define FAKE_HEADER "1234\0??\1??" +#define FAKE_UTC_POS (7 - 4) + +/* Create a fake data segment for database 'sysdb'. */ +static void fake_data_segment(timelib_tzdb *sysdb, + struct location_info **info) +{ + size_t n; + char *data, *p; + + data = malloc(3 * sysdb->index_size + 7); + + p = mempcpy(data, FAKE_HEADER, sizeof(FAKE_HEADER) - 1); + + for (n = 0; n < sysdb->index_size; n++) { + const struct location_info *li; + timelib_tzdb_index_entry *ent; + + ent = (timelib_tzdb_index_entry *)&sysdb->index[n]; + + /* Lookup the timezone name in the hash table. */ + if (strcmp(ent->id, "UTC") == 0) { + ent->pos = FAKE_UTC_POS; + continue; + } + + li = find_zone_info(info, ent->id); + if (li) { + /* If found, append the BC byte and the + * country code; set the position for this + * section of timezone data. */ + ent->pos = (p - data) - 4; + *p++ = '\1'; + *p++ = li->code[0]; + *p++ = li->code[1]; + } + else { + /* If not found, the timezone data can + * point at the header. */ + ent->pos = 0; + } + } + + sysdb->data = (unsigned char *)data; +} + +/* Return the mmap()ed tzfile if found, else NULL. On success, the + * length of the mapped data is placed in *length. */ +static char *map_tzfile(const char *timezone, size_t *length) +{ + char fname[PATH_MAX]; + struct stat st; + char *p; + int fd; + + if (timezone[0] == '\0' || strstr(timezone, "..") != NULL) { + return NULL; + } + + snprintf(fname, sizeof fname, ZONEINFO_PREFIX "/%s", timezone); + + fd = open(fname, O_RDONLY); + if (fd == -1) { + return NULL; + } else if (fstat(fd, &st) != 0 || st.st_size < 21) { + close(fd); + return NULL; + } + + *length = st.st_size; + p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + close(fd); + + return p != MAP_FAILED ? p : NULL; +} + +#endif + +static int inmem_seek_to_tz_position(const unsigned char **tzf, char *timezone, const timelib_tzdb *tzdb) +{ int left = 0, right = tzdb->index_size - 1; #ifdef HAVE_SETLOCALE char *cur_locale = NULL, *tmp; @@ -292,36 +695,124 @@ return 0; } +static int seek_to_tz_position(const unsigned char **tzf, char *timezone, + char **map, size_t *maplen, + const timelib_tzdb *tzdb) +{ + if (tzdb == timezonedb_system) { + char *orig; + + orig = map_tzfile(timezone, maplen); + if (orig == NULL) { + return 0; + } + + (*tzf) = (unsigned char *)orig ; + *map = orig; + + return 1; + } + else { + return inmem_seek_to_tz_position(tzf, timezone, tzdb); + } +} + const timelib_tzdb *timelib_builtin_db(void) { +#ifdef HAVE_SYSTEM_TZDATA + if (timezonedb_system == NULL) { + timelib_tzdb *tmp = malloc(sizeof *tmp); + + tmp->version = "0.system"; + tmp->data = NULL; + create_zone_index(tmp); + system_location_table = create_location_table(); + fake_data_segment(tmp, system_location_table); + timezonedb_system = tmp; + } + + + return timezonedb_system; +#else return &timezonedb_builtin; +#endif } const timelib_tzdb_index_entry *timelib_timezone_builtin_identifiers_list(int *count) { +#ifdef HAVE_SYSTEM_TZDATA + *count = timezonedb_system->index_size; + return timezonedb_system->index; +#else *count = sizeof(timezonedb_idx_builtin) / sizeof(*timezonedb_idx_builtin); return timezonedb_idx_builtin; +#endif } int timelib_timezone_id_is_valid(char *timezone, const timelib_tzdb *tzdb) { const unsigned char *tzf; - return (seek_to_tz_position(&tzf, timezone, tzdb)); + +#ifdef HAVE_SYSTEM_TZDATA + if (tzdb == timezonedb_system) { + char fname[PATH_MAX]; + + if (timezone[0] == '\0' || strstr(timezone, "..") != NULL) { + return 0; + } + + snprintf(fname, sizeof fname, ZONEINFO_PREFIX "/%s", timezone); + + return access(fname, R_OK) == 0 ? 1 : 0; + } +#endif + + return (inmem_seek_to_tz_position(&tzf, timezone, tzdb)); } timelib_tzinfo *timelib_parse_tzfile(char *timezone, const timelib_tzdb *tzdb) { const unsigned char *tzf; + char *memmap = NULL; + size_t maplen; timelib_tzinfo *tmp; - if (seek_to_tz_position(&tzf, timezone, tzdb)) { + if (seek_to_tz_position(&tzf, timezone, &memmap, &maplen, tzdb)) { tmp = timelib_tzinfo_ctor(timezone); read_preamble(&tzf, tmp); read_header(&tzf, tmp); read_transistions(&tzf, tmp); read_types(&tzf, tmp); - read_location(&tzf, tmp); + +#ifdef HAVE_SYSTEM_TZDATA + if (memmap) { + const struct location_info *li; + + /* TZif-style - grok the location info from the system database, + * if possible. */ + + if ((li = find_zone_info(system_location_table, timezone)) != NULL) { + tmp->location.comments = strdup(li->comment); + strncpy(tmp->location.country_code, li->code, 2); + tmp->location.longitude = li->longitude; + tmp->location.latitude = li->latitude; + tmp->bc = 1; + } + else { + strcpy(tmp->location.country_code, "??"); + tmp->bc = 0; + tmp->location.comments = strdup(""); + } + + /* Now done with the mmap segment - discard it. */ + munmap(memmap, maplen); +#endif + } + else { + /* PHP-style - use the embedded info. */ + read_location(&tzf, tmp); + } } else { tmp = NULL; } From Fedora at FamilleCollet.com Wed Jul 15 18:07:25 2009 From: Fedora at FamilleCollet.com (Remi Collet) Date: Wed, 15 Jul 2009 20:07:25 +0200 Subject: [Fedora-php-devel-list] Naming Scheme In-Reply-To: References: Message-ID: <4A5E1ADD.7010307@FamilleCollet.com> Le 15/07/2009 16:31, Christopher Stone a ?crit : > I've seen a couple php-pear packages come through the review pipes > recently with underscores in their names like > php-pear-HTML_Javascript[1] and php-pear-Auth_HTTP[2]. Shouldn't these > have dashes instead of underscores in their names? Yes, I think you're right. >From http://fedoraproject.org/wiki/Packaging/NamingGuidelines "When naming packages for Fedora, the maintainer must use the dash '-' as the delimiter for name parts. The maintainer must NOT use an underscore '_', a plus '+', or a period '.' as a delimiter. " But : "packages where the upstream name naturally contains an underscore are excluded from this." > I thought the > naming guidelines suggested not using underscores? Have the rules > changed? Guidelines seems not clear enough. I've add a explicit comment in pending proposal change to Guidelines https://fedoraproject.org/wiki/PackagingDrafts/PHP Definitively "pear make-rpm-spec" should be the reference ;) Don't know how we should handle this 2 packages... Open a bug ? > > Regards, > Chris > > [1] https://bugzilla.redhat.com/show_bug.cgi?id=508075 > [2] https://bugzilla.redhat.com/show_bug.cgi?id=508082 > > _______________________________________________ > Fedora-php-devel-list mailing list > Fedora-php-devel-list at redhat.com > https://www.redhat.com/mailman/listinfo/fedora-php-devel-list > From Fedora at FamilleCollet.com Thu Jul 16 21:37:44 2009 From: Fedora at FamilleCollet.com (Remi Collet) Date: Thu, 16 Jul 2009 23:37:44 +0200 Subject: [Fedora-php-devel-list] Re: Naming Scheme php-pear-HTML_Javascript and php-pear-Auth_HTTP In-Reply-To: References: <4A5EE390.5040702@FamilleCollet.com> <4A5EE659.9050606@ioa.s.u-tokyo.ac.jp> Message-ID: <4A5F9DA8.30502@FamilleCollet.com> Le 16/07/2009 21:37, Christopher Stone a ?crit : > On Thu, Jul 16, 2009 at 1:35 AM, Mamoru > Tasaka wrote: >> Remi Collet wrote, at 07/16/2009 05:23 PM +9:00: >>> I have just notice than php-pear-HTML_Javascript and php-pear-Auth_HTTP >>> have been approved. >>> >>> I think this package should be named php-pear-HTML-Javascript and >>> php-pear-Auth-HTTP, like all others pear extensions available in Fedora. >>> >> I strongly disagree with your proposition. >> We _must_ honor the naming upstream developer uses as much as possible, >> otherwise >> this will easily confuse people who will actually want to use these packages >> on Fedora. > > Well, one thing is clear. We need to be consistent. We should > identify which php-pear packages are renaming _ to - and which are > not. > >From http://rpms.famillecollet.com/rpmphp/rpm.php?type=pear php-pear-Auth-RADIUS (xulchris) php-pear-Auth-SASL (remi) php-pear-Cache-Lite (remi) php-pear-Console-Color (timj) php-pear-Console-Getargs (remi) php-pear-Console-ProgressBar (remi) php-pear-Console-Table (remi) php-pear-Crypt-Blowfish (xavierb) php-pear-Crypt-CHAP (xulchris) php-pear-Date-Holidays (xulchris) php-pear-Date-Holidays-USA (xulchris) php-pear-DB-DataObject (xulchris) php-pear-DB-DataObject-FormBuilder (xulchris) php-pear-DB-QueryTool (xulchris) php-pear-Event-Dispatcher (remi) php-pear-File-Find (remi) php-pear-File-Passwd (xulchris) php-pear-File-SMBPasswd (xulchris) php-pear-HTML-Common (xulchris) php-pear-HTML-QuickForm (xulchris) php-pear-HTML-QuickForm-advmultiselect (remi) php-pear-HTML-QuickForm-ElementGrid (xulchris) php-pear-HTML-Table (xulchris) php-pear-HTTP-Client (xulchris) php-pear-HTTP-Request (xulchris) php-pear-HTTP-Upload (xulchris) php-pear-Image-Canvas (xulchris) php-pear-Image-Color (xulchris) php-pear-Image-Graph (xulchris) php-pear-Image-GraphViz (xulchris) php-pear-Mail-Mime (remi) php-pear-Mail-mimeDecode (remi) php-pear-Math-Stats (xulchris) php-pear-MDB2-Driver-mysql (xulchris) php-pear-MDB2-Driver-mysqli (trasher) php-pear-MDB2-Driver-pgsql (trasher) php-pear-Net-Curl (xulchris) php-pear-Net-DIME (remi) php-pear-Net-DNS (moixs) php-pear-Net-FTP (remi) php-pear-Net-IPv4 (moixs) php-pear-Net-Ping (remi) php-pear-Net-POP3 (xulchris) php-pear-Net-Sieve (remi) php-pear-Net-SMTP (remi) php-pear-Net-Socket (remi) php-pear-Net-Traceroute (remi) php-pear-Net-URL (xulchris) php-pear-Net-URL-Mapper (xulchris) php-pear-Net-UserAgent-Detect (xulchris) php-pear-Numbers-Roman (xulchris) php-pear-Numbers-Words (xulchris) php-pear-Payment-Process (xulchris) php-pear-PEAR-Command-Packaging (timj) php-pear-PHP-CodeSniffer (icon) php-pear-PHP-Compat (remi) php-pear-PHP-CompatInfo (remi) php-pear-Services-Weather (remi) php-pear-Structures-DataGrid (xulchris) php-pear-Structures-DataGrid-DataSource-Array (xulchris) php-pear-Structures-DataGrid-DataSource-DataObject (xulchris) php-pear-Structures-DataGrid-DataSource-MDB2 (xulchris) php-pear-Structures-DataGrid-DataSource-RSS (xulchris) php-pear-Structures-DataGrid-Renderer-Pager (xulchris) php-pear-Structures-DataGrid-Renderer-Smarty (xulchris) php-pear-Text-Diff (xavierb) php-pear-Validate-Finance-CreditCard (xulchris) php-pear-Var-Dump (remi) php-pear-XML-Beautifier (xulchris) php-pear-XML-Parser (remi) php-pear-XML-RSS (xulchris) php-pear-XML-Serializer (xulchris) php-pear-XML-Util (xulchris) 73 packages php-pear-Auth_HTTP (topdog) php-pear-HTML_Javascript (topdog) 2 packages The first seems to be a "De facto" guidelines followed by all pear extensions packagers. Regards From jorton at redhat.com Fri Jul 17 07:54:25 2009 From: jorton at redhat.com (Joe Orton) Date: Fri, 17 Jul 2009 08:54:25 +0100 Subject: [Fedora-php-devel-list] [seanius@debian.org: Re: [php-maint] Bug#535770: PHP system timezone patch for 5.3?] Message-ID: <20090717075425.GA5028@redhat.com> Forwarding since Sean's mail is not making it through. ----- Forwarded message from sean finney ----- From: sean finney To: PHP Packagers , 535770 at bugs.debian.org, judas.iscariote at gmail.com, fedora-php-devel-list at redhat.com Date: Wed, 15 Jul 2009 01:14:46 +0200 Subject: Re: [php-maint] Bug#535770: PHP system timezone patch for 5.3? User-Agent: Mutt/1.5.20 (2009-06-14) hi joe, some quick notes/observations... in your comments you say: /* Parse an ISO-6709 date as used in zone.tab. Returns end of the s/date/coordinate/ ? :) but more seriously: * in create_zone_index() it looks like find_zone_info(system_zone_info...) is called but system_zone_info isn't initialized until after create_zone_index has returned. * i'm not sure but it seems like there might be a few corresponding free()'s missing from the mallocs/strdups. * it looks like load_zone_table() is called unconditionally, even if it's not needed (i.e. a scall to localtime() will trigger it) * is parsing the comments really necessary? i don't see any php functions that use them. also, before i came to the conclusion that some kind of intermediate hashtable was needed to do the mapping (at which point i gave up and figured i'd wait to hear back from you :), i had done a slightly simpler implementation of the parsing using a clean mmap'd buffer and sscanf with "%ms" type formats which avoids a lot of the hard-coded lengths etc[1]. if you're interested i can hack that code into the load_zone_info (and parse_iso6709) to make a leaner/cleaner/more efficient implementation. also, FYI my posts to the fedora list are being automatically rejected so if i say anything important that should be shared someone should forward it along :) sean [1] 'm' being the sooner-or-later POSIX.1 adoption of the non-standard 'a' GNU libc extension to automatically allocate the parsed strings, which in turn conflicted with the C99 'a' (float) format specifier, hence the new specifier. it requires glibc >= 2.7 btw. ----- End forwarded message ----- From jorton at redhat.com Fri Jul 17 08:27:53 2009 From: jorton at redhat.com (Joe Orton) Date: Fri, 17 Jul 2009 09:27:53 +0100 Subject: [Fedora-php-devel-list] Re: [php-maint] Bug#535770: PHP system timezone patch for 5.3? In-Reply-To: <20090714231445.GB12254@rangda.stickybit.se> References: <20090706205140.GA16626@rangda.stickybit.se> <20090706220531.GA24974@rangda.stickybit.se> <20090707091006.GA4312@redhat.com> <20090714155340.GB2945@redhat.com> <20090714231445.GB12254@rangda.stickybit.se> Message-ID: <20090717082753.GB5028@redhat.com> Hi Sean, sorry I didn't see your comments earlier. On Wed, Jul 15, 2009 at 01:14:46AM +0200, sean finney wrote: > in your comments you say: > > /* Parse an ISO-6709 date as used in zone.tab. Returns end of the > > s/date/coordinate/ ? :) Hah! I've fixed this in patch v7. > but more seriously: > > * in create_zone_index() it looks like > find_zone_info(system_zone_info...) is called but system_zone_info > isn't initialized until after create_zone_index has returned. This was fixed in v6. > * i'm not sure but it seems like there might be a few corresponding free()'s > missing from the mallocs/strdups. Yeah, everything here is malloc'ed but never free'd. We could set it up to be free'd in the date extension's global destructor, but, it would require modifying php_date.c which I am reluctant to do. I'm not sure it makes much difference; the memory will remain allocated for the lifetime of the process in any case, right? > * it looks like load_zone_table() is called unconditionally, even if > it's not needed (i.e. a scall to localtime() will trigger it) I think this is necessary, though I didn't realize that before v6, and didn't explain it at all in the v6 comments. I've added some better commentary now in v7 - the problem is that we need the fake tzdb->data array to be created once the tzdb is created, since timezone_identifiers_list() peeks directly into it. > * is parsing the comments really necessary? i don't see any php functions > that use them. They are exposed by the getLocation() interface - $ php -r '$m = new DateTimeZone("America/New_York"); \ print_r($m->getLocation());' Array ( [country_code] => US [latitude] => 40.71416 [longitude] => -73.99362 [comments] => Eastern Time ) but yes they do seem to be kind of useless, in general. > also, before i came to the conclusion that some kind of intermediate > hashtable was needed to do the mapping (at which point i gave up and > figured i'd wait to hear back from you :), i had done a slightly > simpler implementation of the parsing using a clean mmap'd buffer > and sscanf with "%ms" type formats which avoids a lot of the hard-coded > lengths etc[1]. if you're interested i can hack that code into the > load_zone_info (and parse_iso6709) to make a leaner/cleaner/more efficient > implementation. Does it end up being much simpler without relying on sscanf/%ms? I would rather this code is portable across older glibcs (e.g. so it works on older versions of RHEL). > also, FYI my posts to the fedora list are being automatically rejected > so if i say anything important that should be shared someone should > forward it along :) I've requested that you are whitelisted on the Fedora list. Thanks a lot for reviewing the patch, greatly appreciated! Regards, Joe -------------- next part -------------- Add support for use of the system timezone database, rather than embedding a copy. Discussed upstream but was not desired. History: r7: per Sean Finney's review: simpler lat/long rounding, use stat() not access() to check existence of timezone, improve comments throughout. r6: fix fd leak in r5, fix country code/BC flag use in timezone_identifiers_list() using system db, fix use of PECL timezonedb to override system db, r5: reverts addition of "System/Localtime" fake tzname. updated for 5.3.0, parses zone.tab to pick up mapping between timezone name, country code and long/lat coords r4: added "System/Localtime" tzname which uses /etc/localtime r3: fix a crash if /usr/share/zoneinfo doesn't exist (Raphael Geissert) r2: add filesystem trawl to set up name alias index r1: initial revision --- php-5.3.0/ext/date/lib/parse_tz.c.systzdata +++ php-5.3.0/ext/date/lib/parse_tz.c @@ -20,6 +20,16 @@ #include "timelib.h" +#ifdef HAVE_SYSTEM_TZDATA +#include +#include +#include +#include +#include + +#include "php_scandir.h" +#endif + #include #ifdef HAVE_LOCALE_H @@ -31,7 +41,12 @@ #else #include #endif + +#ifndef HAVE_SYSTEM_TZDATA #include "timezonedb.h" +#endif + +#include #if (defined(__APPLE__) || defined(__APPLE_CC__)) && (defined(__BIG_ENDIAN__) || defined(__LITTLE_ENDIAN__)) # if defined(__LITTLE_ENDIAN__) @@ -51,6 +66,11 @@ static void read_preamble(const unsigned char **tzf, timelib_tzinfo *tz) { + if (memcmp(tzf, "TZif", 4) == 0) { + *tzf += 20; + return; + } + /* skip ID */ *tzf += 4; @@ -253,7 +273,435 @@ void timelib_dump_tzinfo(timelib_tzinfo } } -static int seek_to_tz_position(const unsigned char **tzf, char *timezone, const timelib_tzdb *tzdb) +#ifdef HAVE_SYSTEM_TZDATA + +#ifdef HAVE_SYSTEM_TZDATA_PREFIX +#define ZONEINFO_PREFIX HAVE_SYSTEM_TZDATA_PREFIX +#else +#define ZONEINFO_PREFIX "/usr/share/zoneinfo" +#endif + +/* Hash table entry for the cache of the zone.tab mapping table. */ +struct location_info { + char code[2]; /* Country code. */ + double latitude, longitude; + char name[64]; + char *comment; + struct location_info *next; +}; + +/* System timezone database pointer. */ +static const timelib_tzdb *timezonedb_system = NULL; + +/* Cache of zone.tab location data. */ +static struct location_info **system_location_table; + +/* Size of the zone.tab hash table; a random-ish prime big enough to + * prevent too many collisions. */ +#define LOCINFO_HASH_SIZE (1021) + +/* Hash function for indexing the location_info hash table. */ +static uint32_t tz_hash(const char *str) +{ + const unsigned char *p = (const unsigned char *)str; + uint32_t hash = 5381; + int c; + + while ((c = *p++) != '\0') { + hash = (hash << 5) ^ hash ^ c; + } + + return hash % LOCINFO_HASH_SIZE; +} + +/* Parse an ISO-6709 co-ordinate as used in zone.tab. Returns end of + * the parsed string on success, or NULL on parse error. On success, + * writes the parsed number to *result. */ +static char *parse_iso6709(char *p, double *result) +{ + double v, sign; + char *pend; + size_t len; + + if (*p == '+') + sign = 1.0; + else if (*p == '-') + sign = -1.0; + else + return NULL; + + p++; + for (pend = p; *pend >= '0' && *pend <= '9'; pend++) + ;; + + /* Annoying encoding used by zone.tab has no decimal point, so use + * the length to determine the format: + * + * 4 = DDMM + * 5 = DDDMM + * 6 = DDMMSS + * 7 = DDDMMSS + */ + len = pend - p; + if (len < 4 || len > 7) { + return NULL; + } + + /* p => [D]DD */ + v = (p[0] - '0') * 10.0 + (p[1] - '0'); + p += 2; + if (len == 5 || len == 7) + v = v * 10.0 + (*p++ - '0'); + /* p => MM[SS] */ + v += (10.0 * (p[0] - '0') + + p[1] - '0') / 60.0; + p += 2; + /* p => [SS] */ + if (len > 5) { + v += (10.0 * (p[0] - '0') + + p[1] - '0') / 3600.0; + p += 2; + } + + /* Round to five decimal place, not because it's a good idea, + * but, because the builtin data uses rounded data, so, match + * that. */ + *result = sign * (int)(v * 100000.0 + 0.5) / 100000.0; + + return p; +} + +/* This function parses the zone.tab file to build up the mapping of + * timezone to country code and geographic location, and returns a + * hash table. The hash table is indexed by the function: + * + * tz_hash(timezone-name) + */ +static struct location_info **create_location_table(void) +{ + struct location_info **li, *i; + char zone_tab[PATH_MAX]; + char line[512]; + FILE *fp; + + strncpy(zone_tab, ZONEINFO_PREFIX "/zone.tab", sizeof zone_tab); + + fp = fopen(zone_tab, "r"); + if (!fp) { + return NULL; + } + + li = calloc(LOCINFO_HASH_SIZE, sizeof *li); + + while (fgets(line, sizeof line, fp)) { + char *p = line, *code, *name, *comment; + uint32_t hash; + double latitude, longitude; + + while (isspace(*p)) + p++; + + if (*p == '#' || *p == '\0' || *p == '\n') + continue; + + if (!isalpha(p[0]) || !isalpha(p[1]) || p[2] != '\t') + continue; + + /* code => AA */ + code = p; + p[2] = 0; + p += 3; + + /* coords => [+-][D]DDMM[SS][+-][D]DDMM[SS] */ + p = parse_iso6709(p, &latitude); + if (!p) { + continue; + } + p = parse_iso6709(p, &longitude); + if (!p) { + continue; + } + + if (!p || *p != '\t') { + continue; + } + + /* name = string */ + name = ++p; + while (*p != '\t' && *p && *p != '\n') + p++; + + *p++ = '\0'; + + /* comment = string */ + comment = p; + while (*p != '\t' && *p && *p != '\n') + p++; + + if (*p == '\n' || *p == '\t') + *p = '\0'; + + hash = tz_hash(name); + i = malloc(sizeof *i); + memcpy(i->code, code, 2); + strncpy(i->name, name, sizeof i->name); + i->comment = strdup(comment); + i->longitude = longitude; + i->latitude = latitude; + i->next = li[hash]; + li[hash] = i; + /* printf("%s [%u, %f, %f]\n", name, hash, latitude, longitude); */ + } + + fclose(fp); + + return li; +} + +/* Return location info from hash table, using given timezone name. + * Returns NULL if the name could not be found. */ +const struct location_info *find_zone_info(struct location_info **li, + const char *name) +{ + uint32_t hash = tz_hash(name); + const struct location_info *l; + + if (!li) { + return NULL; + } + + for (l = li[hash]; l; l = l->next) { + if (strcasecmp(l->name, name) == 0) + return l; + } + + return NULL; +} + +/* Filter out some non-tzdata files and the posix/right databases, if + * present. */ +static int index_filter(const struct dirent *ent) +{ + return strcmp(ent->d_name, ".") != 0 + && strcmp(ent->d_name, "..") != 0 + && strcmp(ent->d_name, "posix") != 0 + && strcmp(ent->d_name, "posixrules") != 0 + && strcmp(ent->d_name, "right") != 0 + && strstr(ent->d_name, ".tab") == NULL; +} + +/* Comparison callback for qsort(), used to alpha-sort the index + * array by timezone name. */ +static int sysdbcmp(const void *first, const void *second) +{ + const timelib_tzdb_index_entry *alpha = first, *beta = second; + + return strcmp(alpha->id, beta->id); +} + + +/* Create the zone identifier index by trawling the filesystem. */ +static void create_zone_index(timelib_tzdb *db) +{ + size_t dirstack_size, dirstack_top; + size_t index_size, index_next; + timelib_tzdb_index_entry *db_index; + char **dirstack; + + /* LIFO stack to hold directory entries to scan; each slot is a + * directory name relative to the zoneinfo prefix. */ + dirstack_size = 32; + dirstack = malloc(dirstack_size * sizeof *dirstack); + dirstack_top = 1; + dirstack[0] = strdup(""); + + /* Index array. */ + index_size = 64; + db_index = malloc(index_size * sizeof *db_index); + index_next = 0; + + do { + struct dirent **ents; + char name[PATH_MAX], *top; + int count; + + /* Pop the top stack entry, and iterate through its contents. */ + top = dirstack[--dirstack_top]; + snprintf(name, sizeof name, ZONEINFO_PREFIX "/%s", top); + + count = php_scandir(name, &ents, index_filter, php_alphasort); + + while (count > 0) { + struct stat st; + const char *leaf = ents[count - 1]->d_name; + + snprintf(name, sizeof name, ZONEINFO_PREFIX "/%s/%s", + top, leaf); + + if (strlen(name) && stat(name, &st) == 0) { + /* Name, relative to the zoneinfo prefix. */ + const char *root = top; + + if (root[0] == '/') root++; + + snprintf(name, sizeof name, "%s%s%s", root, + *root ? "/": "", leaf); + + if (S_ISDIR(st.st_mode)) { + if (dirstack_top == dirstack_size) { + dirstack_size *= 2; + dirstack = realloc(dirstack, + dirstack_size * sizeof *dirstack); + } + dirstack[dirstack_top++] = strdup(name); + } + else { + if (index_next == index_size) { + index_size *= 2; + db_index = realloc(db_index, + index_size * sizeof *db_index); + } + + db_index[index_next++].id = strdup(name); + } + } + + free(ents[--count]); + } + + if (count != -1) free(ents); + free(top); + } while (dirstack_top); + + /* Alpha-sort the index array; shouldn't be technically necessary + * but some of the test cases rely on this, and, it matches the + * builtin database. */ + qsort(db_index, index_next, sizeof *db_index, sysdbcmp); + + db->index = db_index; + db->index_size = index_next; + + free(dirstack); +} + +#define FAKE_HEADER "1234\0??\1??" +#define FAKE_BC_POS (0) +#define FAKE_UTC_POS (7 - 4) + +/* Create a fake data segment for database 'sysdb'. This mocks + * up a fake ->data segment for the given timezone database. + * php_date.c::timezone_identifiers_list() looks at data[pos + 4] + * through data[pos + 6] to compare the country code and BC flag, + * which are stored in the builtin data array like: + * + * (pos + 4) => BC flag + * (pos + 5, pos + 6) => Two chars of country code + * + * where pos is the index corresponding to the timezone name. + * + * Timezone names are classified here into three types: + * 1) UTC, which is special + * 2) "normal" zone names + * 3) "backwards-compat" zone names + * + * (boolean logic of the BC flag seems to be inverted, but hey) + * + * UTC is special since it has BC=\1, code = "??" + * "normal" zones exist in zone.tab and have the given c-code and BC=\1 + * "backwards-compat" zones don't exist in zone.tab and have BC=\0 + * + * Since UTC and the BC zones are constant, they are encoded in the + * FAKE_HEADER prefix, and pos pointers index into that. + * + * FAKE_HEADER is hence four random bytes, then the BC zone segment + * (three bytes), then the UTC zone segment (another three). + * + * For all "normal" zones, three bytes are appended to the data array; + * the BC flag, always 1, and the two bytes of country code. + */ +static void fake_data_segment(timelib_tzdb *sysdb, + struct location_info **info) +{ + size_t n; + char *data, *p; + + /* Worst case maximum is 3 bytes per zone, plus the header. */ + data = malloc((3 * sysdb->index_size) + sizeof(FAKE_HEADER) - 1); + + /* Append the fake header, p then = next byte */ + p = mempcpy(data, FAKE_HEADER, sizeof(FAKE_HEADER) - 1); + + for (n = 0; n < sysdb->index_size; n++) { + const struct location_info *li; + timelib_tzdb_index_entry *ent; + + /* Lost const'ness since we're modifying the pos pointer. */ + ent = (timelib_tzdb_index_entry *)&sysdb->index[n]; + + /* Lookup the timezone name in the hash table. */ + if (strcmp(ent->id, "UTC") == 0) { + ent->pos = FAKE_UTC_POS; + continue; + } + + li = find_zone_info(info, ent->id); + if (li) { + /* If found, append the BC byte and the country code; set + * the position index for the timezone to point to + * this. */ + ent->pos = (p - data) - 4; + *p++ = '\x01'; + *p++ = li->code[0]; + *p++ = li->code[1]; + } + else { + /* If not found, the timezone data can + * point at the header. */ + ent->pos = 0; + } + } + + /* Store the fake data array */ + sysdb->data = (unsigned char *)data; +} + +/* Evaluates to true if given timezone name is valid. */ +#define is_valid_tz_name(tz_) (tz_[0] && strstr(tz_, "..") == NULL) + +/* Return the mmap()ed tzfile if found, else NULL. On success, the + * length of the mapped data is placed in *length. */ +static char *map_tzfile(const char *timezone, size_t *length) +{ + char fname[PATH_MAX]; + struct stat st; + char *p; + int fd; + + if (!is_valid_tz_name(timezone)) { + return NULL; + } + + snprintf(fname, sizeof fname, ZONEINFO_PREFIX "/%s", timezone); + + fd = open(fname, O_RDONLY); + if (fd == -1) { + return NULL; + } else if (fstat(fd, &st) != 0 || st.st_size < 21) { + close(fd); + return NULL; + } + + *length = st.st_size; + p = mmap(NULL, st.st_size, PROT_READ, MAP_SHARED, fd, 0); + close(fd); + + return p != MAP_FAILED ? p : NULL; +} +#endif + +/* seek_to_tz_position() for a builtin/external database. */ +static int inmem_seek_to_tz_position(const unsigned char **tzf, + char *timezone, const timelib_tzdb *tzdb) { int left = 0, right = tzdb->index_size - 1; #ifdef HAVE_SETLOCALE @@ -292,36 +740,131 @@ static int seek_to_tz_position(const uns return 0; } +/* Modified seek_to_tz_position wrapper which handles the system + * database and the builtin/external databases in the same way. + * Returns zero on failure on non-zero on success. On success, (*map, + * *maplen) is an mmap'ed region if *map is non-NULL, and must be + * munmaped after use. */ +static int seek_to_tz_position(const unsigned char **tzf, char *timezone, + char **map, size_t *maplen, + const timelib_tzdb *tzdb) +{ +#ifdef HAVE_SYSTEM_TZDATA + if (tzdb == timezonedb_system) { + char *orig; + + orig = map_tzfile(timezone, maplen); + if (orig == NULL) { + return 0; + } + + (*tzf) = (unsigned char *)orig ; + *map = orig; + + return 1; + } + else +#endif + { + return inmem_seek_to_tz_position(tzf, timezone, tzdb); + } +} + const timelib_tzdb *timelib_builtin_db(void) { +#ifdef HAVE_SYSTEM_TZDATA + if (timezonedb_system == NULL) { + timelib_tzdb *tmp = malloc(sizeof *tmp); + + tmp->version = "0.system"; + tmp->data = NULL; + create_zone_index(tmp); + system_location_table = create_location_table(); + fake_data_segment(tmp, system_location_table); + timezonedb_system = tmp; + } + + return timezonedb_system; +#else return &timezonedb_builtin; +#endif } const timelib_tzdb_index_entry *timelib_timezone_builtin_identifiers_list(int *count) { +#ifdef HAVE_SYSTEM_TZDATA + *count = timezonedb_system->index_size; + return timezonedb_system->index; +#else *count = sizeof(timezonedb_idx_builtin) / sizeof(*timezonedb_idx_builtin); return timezonedb_idx_builtin; +#endif } int timelib_timezone_id_is_valid(char *timezone, const timelib_tzdb *tzdb) { const unsigned char *tzf; - return (seek_to_tz_position(&tzf, timezone, tzdb)); + +#ifdef HAVE_SYSTEM_TZDATA + if (tzdb == timezonedb_system) { + char fname[PATH_MAX]; + struct stat st; + + if (!is_valid_tz_name(timezone)) { + return 0; + } + + snprintf(fname, sizeof fname, ZONEINFO_PREFIX "/%s", timezone); + + return stat(fname, &st) == 0 && S_ISREG(st.st_mode); + } +#endif + + return (inmem_seek_to_tz_position(&tzf, timezone, tzdb)); } timelib_tzinfo *timelib_parse_tzfile(char *timezone, const timelib_tzdb *tzdb) { const unsigned char *tzf; + char *memmap = NULL; + size_t maplen; timelib_tzinfo *tmp; - if (seek_to_tz_position(&tzf, timezone, tzdb)) { + if (seek_to_tz_position(&tzf, timezone, &memmap, &maplen, tzdb)) { tmp = timelib_tzinfo_ctor(timezone); read_preamble(&tzf, tmp); read_header(&tzf, tmp); read_transistions(&tzf, tmp); read_types(&tzf, tmp); - read_location(&tzf, tmp); + +#ifdef HAVE_SYSTEM_TZDATA + if (memmap) { + const struct location_info *li; + + /* TZif-style - grok the location info from the system database, + * if possible. */ + if ((li = find_zone_info(system_location_table, timezone)) != NULL) { + tmp->location.comments = strdup(li->comment); + strncpy(tmp->location.country_code, li->code, 2); + tmp->location.longitude = li->longitude; + tmp->location.latitude = li->latitude; + tmp->bc = 1; + } + else { + strcpy(tmp->location.country_code, "??"); + tmp->bc = 0; + tmp->location.comments = strdup(""); + } + + /* Now done with the mmap segment - discard it. */ + munmap(memmap, maplen); +#endif + } + else { + /* PHP-style - use the embedded info. */ + read_location(&tzf, tmp); + } } else { tmp = NULL; } --- php-5.3.0/ext/date/lib/timelib.m4.systzdata +++ php-5.3.0/ext/date/lib/timelib.m4 @@ -78,3 +78,17 @@ stdlib.h dnl Check for strtoll, atoll AC_CHECK_FUNCS(strtoll atoll strftime) + +PHP_ARG_WITH(system-tzdata, for use of system timezone data, +[ --with-system-tzdata[=DIR] to specify use of system timezone data], +no, no) + +if test "$PHP_SYSTEM_TZDATA" != "no"; then + AC_DEFINE(HAVE_SYSTEM_TZDATA, 1, [Define if system timezone data is used]) + + if test "$PHP_SYSTEM_TZDATA" != "yes"; then + AC_DEFINE_UNQUOTED(HAVE_SYSTEM_TZDATA_PREFIX, "$PHP_SYSTEM_TZDATA", + [Define for location of system timezone data]) + fi +fi + From Fedora at FamilleCollet.com Fri Jul 17 15:13:10 2009 From: Fedora at FamilleCollet.com (Remi Collet) Date: Fri, 17 Jul 2009 17:13:10 +0200 Subject: [Fedora-php-devel-list] Re: Naming Scheme php-pear-HTML_Javascript and php-pear-Auth_HTTP In-Reply-To: <4A6091E3.7070103@ioa.s.u-tokyo.ac.jp> References: <4A5EE390.5040702@FamilleCollet.com> <4A5EE659.9050606@ioa.s.u-tokyo.ac.jp> <4A5F0A80.7080605@ioa.s.u-tokyo.ac.jp> <4A5FFD5C.70700@ioa.s.u-tokyo.ac.jp> <4A6091E3.7070103@ioa.s.u-tokyo.ac.jp> Message-ID: <4A609506.4070705@FamilleCollet.com> Le 17/07/2009 16:59, Mamoru Tasaka a ?crit : > Christopher Stone wrote, at 07/17/2009 02:22 PM +9:00: >> On Thu, Jul 16, 2009 at 9:26 PM, Mamoru >> Tasaka wrote: >>> Christopher Stone wrote, at 07/17/2009 11:59 AM +9:00: >>>> On Thu, Jul 16, 2009 at 1:35 AM, Mamoru >>>> Tasaka wrote: >>>>> You must explain why you want to force to change understore to hyphen, >>>>> even if installed files actually uses understore in its name. >>>> So trying to think back to when we originally created the PHP >>>> guidelines, specifically for php-pear, I think we had already >>>> discussed this issue. You may want to search the packaging list >>>> archives, I forget when we formulated the guidelines. Anyway, I think >>>> the logic behind it was that the perl packages converted the :: to - >>>> in their packages. So in order to be consistent with the perl packages >>>> we used the same convention in the php-pear packages. There might be >>>> some other technical reason why fedora converts upstream's :: to - for >>>> perl packages which I'm not aware of however. But IIRC, that was the >>>> logic behind the package naming. >>> >>> perl modules have some underscore naming like >>> perl-Convert-NLS_DATE_FORMAT. We have no reason we must apply perl >>> naming rule here and again there is no reason we should convert >>> underscore >>> to hyphen >>> which would just cause confusion. >>> >>> Please think in the way that we need less guidelines as much as >>> possible. >>> If you have some reason *specific to php-pear*, please explain, and such >>> reason must be written somewhere properly. >>> >>> Mamoru >>> >> >> Then I guess we should search the packaging list archives and see if >> we can find the reasoning when the guidelines were being formulated. >> It must have been discussed or else the entire packaging committee >> misunderstood the guidelines at the time. The majority of the >> packages are owned by Remi and myself. I don't know how much work it >> will be to rename all the packages. Hi, First, I think this discussion should go to fedora-php-devel (a public place), as I'd like to heard from others (tim please ?) > > So at least for now we cannot justify why underscore should be converted > to hyphen, right? I'm still not convinced.. but probably because I hate underscore... > For me it is strange that you or Remi don't remember > that (, however I guess there was actually no _real_ reason anyway). > > If we cannot find out what was discussed, we must withdraw the proposal > about converting underscore to hyphen and at least new packages must > use underscore if upstream's naming uses it. > (However I think remaing php-pear related packages on Fedora is preferable > and it is better that such renaming should be begun as early as possible) :( really a big work > > Regards, > Mamoru > Best regards. From chris.stone at gmail.com Fri Jul 17 19:26:40 2009 From: chris.stone at gmail.com (Christopher Stone) Date: Fri, 17 Jul 2009 12:26:40 -0700 Subject: [Fedora-php-devel-list] Re: Naming Scheme php-pear-HTML_Javascript and php-pear-Auth_HTTP In-Reply-To: <4A609506.4070705@FamilleCollet.com> References: <4A5EE390.5040702@FamilleCollet.com> <4A5EE659.9050606@ioa.s.u-tokyo.ac.jp> <4A5F0A80.7080605@ioa.s.u-tokyo.ac.jp> <4A5FFD5C.70700@ioa.s.u-tokyo.ac.jp> <4A6091E3.7070103@ioa.s.u-tokyo.ac.jp> <4A609506.4070705@FamilleCollet.com> Message-ID: On Fri, Jul 17, 2009 at 8:13 AM, Remi Collet wrote: > > I'm still not convinced.. but probably because I hate underscore... > > :( ? really a big work Indeed, any shell scripts or volunteers to help implement the conversion would go a long way towards actually seeing this get done in a timely fashion. From lists at timj.co.uk Sat Jul 18 09:24:26 2009 From: lists at timj.co.uk (Tim Jackson) Date: Sat, 18 Jul 2009 10:24:26 +0100 Subject: [Fedora-php-devel-list] Re: Naming Scheme php-pear-HTML_Javascript and php-pear-Auth_HTTP In-Reply-To: <4A609506.4070705@FamilleCollet.com> References: <4A5EE390.5040702@FamilleCollet.com> <4A5EE659.9050606@ioa.s.u-tokyo.ac.jp> <4A5F0A80.7080605@ioa.s.u-tokyo.ac.jp> <4A5FFD5C.70700@ioa.s.u-tokyo.ac.jp> <4A6091E3.7070103@ioa.s.u-tokyo.ac.jp> <4A609506.4070705@FamilleCollet.com> Message-ID: <4A6194CA.6000106@timj.co.uk> On 17/07/09 16:13, Remi Collet wrote: > First, I think this discussion should go to fedora-php-devel (a public > place), as I'd like to heard from others (tim please ?) I've had a look this morning through some really old archives of fedora-extras-list and fedora-packaging. I submitted the first "real" package of a PEAR module that wasn't part of php-pear back in Dec 05: https://bugzilla.redhat.com/show_bug.cgi?id=176733 That was php-pear-DB, which doesn't involve a package name with an underscore, so that doesn't help :-) It does however refers back to an earlier bug from Nov 05 that I filed about Provides in php-pear: https://bugzilla.redhat.com/show_bug.cgi?id=173806 At that point "pear makerpm" generated packages called PEAR::Foo_Bar as per upstream; the discussion in the above bug about naming was slightly different as it related to Provides; Joe plumped for "php-pear(Foo_Bar)" as Provide naming, which still stands and seems entirely reasonable. At the time I incidentally mentioned that my preference for package naming was php-pear-Foo_Bar. I can't find any discussions of what happened after that, but the next package seems to have been (March 06) PEAR_Command_Packaging (also by me, reviewed by Christopher): https://bugzilla.redhat.com/show_bug.cgi?id=185423 which was using the php-pear-Foo-Bar naming. However, I'm pretty sure that the naming format was already implicitly agreed by then, because: a) I seem to remember following a then generally-agreed if unwritten format when creating the spec, and b) there is no debate in the review bug about the naming. My best guess is that it came about due to the NamingGuidelines specifying not to use underscores. (I'm not sure whether the current exception about excluding packages where the name naturally includes an underscore existed then; I suspect not). My opinions: 1. Current packages should follow the existing conventions. All current packages bar two are php-pear-Foo-Bar. HTML_Javascript and Auth_HTTP should fall into line. Let's be consistent. 2. Remi's suggestion to update the Guidelines to make this explicit is good. 3. If we were building a new distro from scratch tomorrow, with hindsight my personal preference would be to use php-pear-Foo_Bar. 4. Notwithstanding (3), I cannot see *any* point whatsoever in undergoing a massive exercise in revising the guidelines and renaming all existing packages. I would certainly not expend any time on it myself. Tim From lists at timj.co.uk Sat Jul 18 09:57:47 2009 From: lists at timj.co.uk (Tim Jackson) Date: Sat, 18 Jul 2009 10:57:47 +0100 Subject: [Fedora-php-devel-list] For FPC : Change proposal to PHP Guidelines In-Reply-To: <4A5CB47E.2040602@FamilleCollet.com> References: <4A5CB47E.2040602@FamilleCollet.com> Message-ID: <4A619C9B.2030100@timj.co.uk> On 14/07/09 17:38, Remi Collet wrote: > We have some pending minor issues/questions with PHP packaging we should > make clearer : Thanks for doing this work Remi. > 1/ use of /usr/share/php > > => 1 folder per library Agreed, but I would change the word "extension" to "software" to avoid confusion with binary extensions, and re-word this a bit make the text clearer and more specific, for example: "Non-PEAR PHP software which provides shared libraries should put its PHP source files for such shared libraries in a subfolder of /usr/share/php, named according to the name of the software. For example, a library called "Whizz_Bang" (with a RPM called php-something-Whizz-Bang) would put the PHP source files for its shared libraries in /usr/share/php/Whizz_Bang ." > 2/ conditional in ABI check and in post/postun scriplet > > This conditions are present to maintain compatibility with older PHP > version (5.1.6 on EL-5) and could be removed if package requires a > recent version (> 5.2) I would suggest an easier-to-read introduction: "To be certain that a binary extension will run correctly with a particular version of PHP, it is necessary to check that a particular package has both API and ABIs matching the installed version of PHP. The mechanism for doing this has evolved over time and is as follows:" For the second part, I would split the specfile template into three parts as follows: For Fedora (all current versions): BuildRequires: php-devel Requires: php(zend-abi) = %{php_zend_api} Requires: php(api) = %{php_core_api} For Fedora EPEL 5: BuildRequires: php-devel Requires: php-api = %{php_apiver} There is no way of checking the ABI with packages for Fedora EPEL 5. For a spec file which is compatible with both Fedora and EPEL 5: BuildRequires: php-devel %if %{?php_zend_api}0 Requires: php(zend-abi) = %{php_zend_api} Requires: php(api) = %{php_core_api} %else Requires: php-api = %{php_apiver} %endif No API/ABI dependencies are available for Fedora EPEL 4 packages. > 3/ ABI check [...] > Module compiled with module API=20060613 > PHP compiled with module API=20090626 > > It seems clear it should be mandatory for all C extension. Definitely. Tim From Fedora at FamilleCollet.com Sat Jul 18 10:48:44 2009 From: Fedora at FamilleCollet.com (Remi Collet) Date: Sat, 18 Jul 2009 12:48:44 +0200 Subject: [Fedora-packaging] Re: [Fedora-php-devel-list] For FPC : Change proposal to PHP Guidelines In-Reply-To: <4A619C9B.2030100@timj.co.uk> References: <4A5CB47E.2040602@FamilleCollet.com> <4A619C9B.2030100@timj.co.uk> Message-ID: <4A61A88C.1000407@FamilleCollet.com> Le 18/07/2009 11:57, Tim Jackson a ?crit : Thanks for your corrections (applied) > There is no way of checking the ABI with packages for Fedora EPEL 5. In fact, when I rebuild all extensions (for 5.3) I notice the solution used by APC which is very specific to EL-5 %global php_zendabiver %((echo 0; php -i 2>/dev/null | sed -n 's/^PHP Extension => //p') | tail -1) Requires: php-zend-abi = %{php_zendabiver} Could be usefull, as php 5.1.x and 5.2.x provides both the same API (20041225) but different ABI (20050922 < 20060613) $ rpm -qp --provides /tmp/php-common-5.1.6-23.el5.i386.rpm | grep 200 php-api = 20041225 php-zend-abi = 20050922 Remi. From jorton at redhat.com Sun Jul 19 12:32:46 2009 From: jorton at redhat.com (Joe Orton) Date: Sun, 19 Jul 2009 13:32:46 +0100 Subject: [Fedora-php-devel-list] Re: Naming Scheme php-pear-HTML_Javascript and php-pear-Auth_HTTP In-Reply-To: <4A6194CA.6000106@timj.co.uk> References: <4A5EE390.5040702@FamilleCollet.com> <4A5EE659.9050606@ioa.s.u-tokyo.ac.jp> <4A5F0A80.7080605@ioa.s.u-tokyo.ac.jp> <4A5FFD5C.70700@ioa.s.u-tokyo.ac.jp> <4A6091E3.7070103@ioa.s.u-tokyo.ac.jp> <4A609506.4070705@FamilleCollet.com> <4A6194CA.6000106@timj.co.uk> Message-ID: <20090719123246.GA4036@redhat.com> On Sat, Jul 18, 2009 at 10:24:26AM +0100, Tim Jackson wrote: > My opinions: > > 1. Current packages should follow the existing conventions. All current > packages bar two are php-pear-Foo-Bar. HTML_Javascript and Auth_HTTP > should fall into line. Let's be consistent. > > 2. Remi's suggestion to update the Guidelines to make this explicit is good. > > 3. If we were building a new distro from scratch tomorrow, with hindsight my > personal preference would be to use php-pear-Foo_Bar. > > 4. Notwithstanding (3), I cannot see *any* point whatsoever in undergoing a > massive exercise in revising the guidelines and renaming all existing > packages. I would certainly not expend any time on it myself. I agree with everything above. Regards, Joe