Download | Plain Text | No Line Numbers


  1. diff -Naur htscanner-cvs/ap_fnmatch.c htscanner/ap_fnmatch.c
  2. --- htscanner-cvs/ap_fnmatch.c 1970-01-01 01:00:00.000000000 +0100
  3. +++ htscanner/ap_fnmatch.c 2007-07-09 02:11:27.000000000 +0200
  4. @@ -0,0 +1,263 @@
  5. +/* Licensed to the Apache Software Foundation (ASF) under one or more
  6. + * contributor license agreements. See the NOTICE file distributed with
  7. + * this work for additional information regarding copyright ownership.
  8. + * The ASF licenses this file to You under the Apache License, Version 2.0
  9. + * (the "License"); you may not use this file except in compliance with
  10. + * the License. You may obtain a copy of the License at
  11. + *
  12. + * http://www.apache.org/licenses/LICENSE-2.0
  13. + *
  14. + * Unless required by applicable law or agreed to in writing, software
  15. + * distributed under the License is distributed on an "AS IS" BASIS,
  16. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  17. + * See the License for the specific language governing permissions and
  18. + * limitations under the License.
  19. + */
  20. +
  21. +/*
  22. + * Copyright (c) 1989, 1993, 1994
  23. + * The Regents of the University of California. All rights reserved.
  24. + *
  25. + * This code is derived from software contributed to Berkeley by
  26. + * Guido van Rossum.
  27. + *
  28. + * Redistribution and use in source and binary forms, with or without
  29. + * modification, are permitted provided that the following conditions
  30. + * are met:
  31. + * 1. Redistributions of source code must retain the above copyright
  32. + * notice, this list of conditions and the following disclaimer.
  33. + * 2. Redistributions in binary form must reproduce the above copyright
  34. + * notice, this list of conditions and the following disclaimer in the
  35. + * documentation and/or other materials provided with the distribution.
  36. + * 3. All advertising materials mentioning features or use of this software
  37. + * must display the following acknowledgement:
  38. + * This product includes software developed by the University of
  39. + * California, Berkeley and its contributors.
  40. + * 4. Neither the name of the University nor the names of its contributors
  41. + * may be used to endorse or promote products derived from this software
  42. + * without specific prior written permission.
  43. + *
  44. + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  45. + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  46. + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  47. + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  48. + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  49. + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  50. + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  51. + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  52. + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  53. + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  54. + * SUCH DAMAGE.
  55. + */
  56. +
  57. +#if defined(LIBC_SCCS) && !defined(lint)
  58. +static char sccsid[] = "@(#)fnmatch.c 8.2 (Berkeley) 4/16/94";
  59. +#endif /* LIBC_SCCS and not lint */
  60. +
  61. +/*
  62. + * Function fnmatch() as specified in POSIX 1003.2-1992, section B.6.
  63. + * Compares a filename or pathname to a pattern.
  64. + */
  65. +
  66. +#include "ap_fnmatch.h"
  67. +#include <string.h>
  68. +#include <stdio.h>
  69. +
  70. +#define ap_tolower(c) (tolower(((unsigned char)(c))))
  71. +#define EOS '\0'
  72. +
  73. +static const char *rangematch(const char *, int, int);
  74. +
  75. +int ap_fnmatch(const char *pattern, const char *string, int flags)
  76. +{
  77. + const char *stringstart;
  78. + char c, test;
  79. +
  80. + for (stringstart = string;;) {
  81. + switch (c = *pattern++) {
  82. + case EOS:
  83. + return (*string == EOS ? 0 : FNM_NOMATCH);
  84. + case '?':
  85. + if (*string == EOS) {
  86. + return (FNM_NOMATCH);
  87. + }
  88. + if (*string == '/' && (flags & FNM_PATHNAME)) {
  89. + return (FNM_NOMATCH);
  90. + }
  91. + if (*string == '.' && (flags & FNM_PERIOD) &&
  92. + (string == stringstart ||
  93. + ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) {
  94. + return (FNM_NOMATCH);
  95. + }
  96. + ++string;
  97. + break;
  98. + case '*':
  99. + c = *pattern;
  100. + /* Collapse multiple stars. */
  101. + while (c == '*') {
  102. + c = *++pattern;
  103. + }
  104. +
  105. + if (*string == '.' && (flags & FNM_PERIOD) &&
  106. + (string == stringstart ||
  107. + ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) {
  108. + return (FNM_NOMATCH);
  109. + }
  110. +
  111. + /* Optimize for pattern with * at end or before /. */
  112. + if (c == EOS) {
  113. + if (flags & FNM_PATHNAME) {
  114. + return (strchr(string, '/') == NULL ? 0 : FNM_NOMATCH);
  115. + }
  116. + else {
  117. + return (0);
  118. + }
  119. + }
  120. + else if (c == '/' && flags & FNM_PATHNAME) {
  121. + if ((string = strchr(string, '/')) == NULL) {
  122. + return (FNM_NOMATCH);
  123. + }
  124. + break;
  125. + }
  126. +
  127. + /* General case, use recursion. */
  128. + while ((test = *string) != EOS) {
  129. + if (!ap_fnmatch(pattern, string, flags & ~FNM_PERIOD)) {
  130. + return (0);
  131. + }
  132. + if (test == '/' && flags & FNM_PATHNAME) {
  133. + break;
  134. + }
  135. + ++string;
  136. + }
  137. + return (FNM_NOMATCH);
  138. + case '[':
  139. + if (*string == EOS) {
  140. + return (FNM_NOMATCH);
  141. + }
  142. + if (*string == '/' && flags & FNM_PATHNAME) {
  143. + return (FNM_NOMATCH);
  144. + }
  145. + if (*string == '.' && (flags & FNM_PERIOD) &&
  146. + (string == stringstart ||
  147. + ((flags & FNM_PATHNAME) && *(string - 1) == '/'))) {
  148. + return (FNM_NOMATCH);
  149. + }
  150. + if ((pattern = rangematch(pattern, *string, flags)) == NULL) {
  151. + return (FNM_NOMATCH);
  152. + }
  153. + ++string;
  154. + break;
  155. + case '\\':
  156. + if (!(flags & FNM_NOESCAPE)) {
  157. + if ((c = *pattern++) == EOS) {
  158. + c = '\\';
  159. + --pattern;
  160. + }
  161. + }
  162. + /* FALLTHROUGH */
  163. + default:
  164. + if (flags & FNM_CASE_BLIND) {
  165. + if (ap_tolower(c) != ap_tolower(*string)) {
  166. + return (FNM_NOMATCH);
  167. + }
  168. + }
  169. + else if (c != *string) {
  170. + return (FNM_NOMATCH);
  171. + }
  172. + string++;
  173. + break;
  174. + }
  175. + /* NOTREACHED */
  176. + }
  177. +}
  178. +
  179. +static const char *rangematch(const char *pattern, int test, int flags)
  180. +{
  181. + int negate, ok;
  182. + char c, c2;
  183. +
  184. + /*
  185. + * A bracket expression starting with an unquoted circumflex
  186. + * character produces unspecified results (IEEE 1003.2-1992,
  187. + * 3.13.2). This implementation treats it like '!', for
  188. + * consistency with the regular expression syntax.
  189. + * J.T. Conklin (conklin@ngai.kaleida.com)
  190. + */
  191. + if ((negate = (*pattern == '!' || *pattern == '^'))) {
  192. + ++pattern;
  193. + }
  194. +
  195. + for (ok = 0; (c = *pattern++) != ']';) {
  196. + if (c == '\\' && !(flags & FNM_NOESCAPE)) {
  197. + c = *pattern++;
  198. + }
  199. + if (c == EOS) {
  200. + return (NULL);
  201. + }
  202. + if (*pattern == '-' && (c2 = *(pattern + 1)) != EOS && c2 != ']') {
  203. + pattern += 2;
  204. + if (c2 == '\\' && !(flags & FNM_NOESCAPE)) {
  205. + c2 = *pattern++;
  206. + }
  207. + if (c2 == EOS) {
  208. + return (NULL);
  209. + }
  210. + if ((c <= test && test <= c2)
  211. + || ((flags & FNM_CASE_BLIND)
  212. + && ((ap_tolower(c) <= ap_tolower(test))
  213. + && (ap_tolower(test) <= ap_tolower(c2))))) {
  214. + ok = 1;
  215. + }
  216. + }
  217. + else if ((c == test)
  218. + || ((flags & FNM_CASE_BLIND)
  219. + && (ap_tolower(c) == ap_tolower(test)))) {
  220. + ok = 1;
  221. + }
  222. + }
  223. + return (ok == negate ? NULL : pattern);
  224. +}
  225. +
  226. +
  227. +/* This function is an Apache addition */
  228. +/* return non-zero if pattern has any glob chars in it */
  229. +int ap_is_fnmatch(const char *pattern)
  230. +{
  231. + int nesting;
  232. +
  233. + nesting = 0;
  234. + while (*pattern) {
  235. + switch (*pattern) {
  236. + case '?':
  237. + case '*':
  238. + return 1;
  239. +
  240. + case '\\':
  241. + if (*pattern++ == '\0') {
  242. + return 0;
  243. + }
  244. + break;
  245. +
  246. + case '[': /* '[' is only a glob if it has a matching ']' */
  247. + ++nesting;
  248. + break;
  249. +
  250. + case ']':
  251. + if (nesting) {
  252. + return 1;
  253. + }
  254. + break;
  255. + }
  256. + ++pattern;
  257. + }
  258. + return 0;
  259. +}
  260. +/*
  261. + * Local variables:
  262. + * tab-width: 8
  263. + * c-basic-offset: 8
  264. + * End:
  265. + * vim600: noet sw=8 ts=8 fdm=marker
  266. + * vim<600: noet sw=8 ts=8
  267. + */
  268. diff -Naur htscanner-cvs/ap_fnmatch.h htscanner/ap_fnmatch.h
  269. --- htscanner-cvs/ap_fnmatch.h 1970-01-01 01:00:00.000000000 +0100
  270. +++ htscanner/ap_fnmatch.h 2007-07-09 02:11:48.000000000 +0200
  271. @@ -0,0 +1,70 @@
  272. +/*-
  273. + * Copyright (c) 1992, 1993
  274. + * The Regents of the University of California. All rights reserved.
  275. + *
  276. + * Redistribution and use in source and binary forms, with or without
  277. + * modification, are permitted provided that the following conditions
  278. + * are met:
  279. + * 1. Redistributions of source code must retain the above copyright
  280. + * notice, this list of conditions and the following disclaimer.
  281. + * 2. Redistributions in binary form must reproduce the above copyright
  282. + * notice, this list of conditions and the following disclaimer in the
  283. + * documentation and/or other materials provided with the distribution.
  284. + * 3. All advertising materials mentioning features or use of this software
  285. + * must display the following acknowledgement:
  286. + * This product includes software developed by the University of
  287. + * California, Berkeley and its contributors.
  288. + * 4. Neither the name of the University nor the names of its contributors
  289. + * may be used to endorse or promote products derived from this software
  290. + * without specific prior written permission.
  291. + *
  292. + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
  293. + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  294. + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
  295. + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
  296. + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  297. + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
  298. + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
  299. + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
  300. + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
  301. + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
  302. + * SUCH DAMAGE.
  303. + *
  304. + * @(#)fnmatch.h 8.1 (Berkeley) 6/2/93
  305. + */
  306. +
  307. +/* This file has been modified by the Apache Group. */
  308. +
  309. +#ifndef _FNMATCH_H_
  310. +#define _FNMATCH_H_
  311. +
  312. +#ifdef __cplusplus
  313. +extern "C" {
  314. +#endif
  315. +
  316. +#define FNM_NOMATCH 1 /* Match failed. */
  317. +
  318. +#define FNM_NOESCAPE 0x01 /* Disable backslash escaping. */
  319. +#define FNM_PATHNAME 0x02 /* Slash must be matched by slash. */
  320. +#define FNM_PERIOD 0x04 /* Period must be matched by period. */
  321. +/* This flag is an Apache addition */
  322. +#define FNM_CASE_BLIND 0x08 /* Compare characters case-insensitively. */
  323. +
  324. +int ap_fnmatch(const char *, const char *, int);
  325. +
  326. +/* this function is an Apache addition */
  327. +extern int ap_is_fnmatch(const char *);
  328. +
  329. +#ifdef __cplusplus
  330. +}
  331. +#endif
  332. +
  333. +#endif /* !_FNMATCH_H_ */
  334. +/*
  335. + * Local variables:
  336. + * tab-width: 8
  337. + * c-basic-offset: 8
  338. + * End:
  339. + * vim600: noet sw=8 ts=8 fdm=marker
  340. + * vim<600: noet sw=8 ts=8
  341. + */
  342. diff -Naur htscanner-cvs/ap_util.c htscanner/ap_util.c
  343. --- htscanner-cvs/ap_util.c 1970-01-01 01:00:00.000000000 +0100
  344. +++ htscanner/ap_util.c 2007-07-09 02:12:19.000000000 +0200
  345. @@ -0,0 +1,111 @@
  346. +/* Licensed to the Apache Software Foundation (ASF) under one or more
  347. + * contributor license agreements. See the NOTICE file distributed with
  348. + * this work for additional information regarding copyright ownership.
  349. + * The ASF licenses this file to You under the Apache License, Version 2.0
  350. + * (the "License"); you may not use this file except in compliance with
  351. + * the License. You may obtain a copy of the License at
  352. + *
  353. + * http://www.apache.org/licenses/LICENSE-2.0
  354. + *
  355. + * Unless required by applicable law or agreed to in writing, software
  356. + * distributed under the License is distributed on an "AS IS" BASIS,
  357. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  358. + * See the License for the specific language governing permissions and
  359. + * limitations under the License.
  360. + */
  361. +
  362. +/*
  363. + * util.c: string utility things
  364. + *
  365. + * 3/21/93 Rob McCool
  366. + * 1995-96 Many changes by the Apache Group
  367. + *
  368. + */
  369. +
  370. +#include "ap_util.h"
  371. +
  372. +void ap_no2slash(char *name)
  373. +{
  374. + char *d, *s;
  375. +
  376. + s = d = name;
  377. +
  378. +#ifdef PHP_WIN32
  379. + /* Check for UNC names. Leave leading two slashes. */
  380. + if (s[0] == '/' && s[1] == '/')
  381. + *d++ = *s++;
  382. +#endif
  383. +
  384. + while (*s) {
  385. + if ((*d++ = *s) == '/') {
  386. + do {
  387. + ++s;
  388. + } while (*s == '/');
  389. + }
  390. + else {
  391. + ++s;
  392. + }
  393. + }
  394. + *d = '\0';
  395. +}
  396. +
  397. +
  398. +/*
  399. + * copy at most n leading directories of s into d
  400. + * d should be at least as large as s plus 1 extra byte
  401. + * assumes n > 0
  402. + * the return value is the ever useful pointer to the trailing \0 of d
  403. + *
  404. + * examples:
  405. + * /a/b, 1 ==> /
  406. + * /a/b, 2 ==> /a/
  407. + * /a/b, 3 ==> /a/b/
  408. + * /a/b, 4 ==> /a/b/
  409. + *
  410. + * MODIFIED FOR HAVE_DRIVE_LETTERS and NETWARE environments,
  411. + * so that if n == 0, "/" is returned in d with n == 1
  412. + * and s == "e:/test.html", "e:/" is returned in d
  413. + * *** See also directory_walk in src/main/http_request.c
  414. + */
  415. +char * ap_make_dirstr_prefix(char *d, const char *s, int n)
  416. +{
  417. +#if defined(PHP_WIN32) || defined(NETWARE)
  418. + if (!n) {
  419. + *d = '/';
  420. + *++d = '\0';
  421. + return (d);
  422. + }
  423. +#endif /* def HAVE_DRIVE_LETTERS || NETWARE */
  424. + for (;;) {
  425. + *d = *s;
  426. + if (*d == '\0') {
  427. + *d = '/';
  428. + break;
  429. + }
  430. + if (*d == '/' && (--n) == 0)
  431. + break;
  432. + ++d;
  433. + ++s;
  434. + }
  435. + *++d = 0;
  436. + return (d);
  437. +}
  438. +
  439. +
  440. +int ap_count_dirs(const char *path)
  441. +{
  442. + register int x, n;
  443. +
  444. + for (x = 0, n = 0; path[x]; x++)
  445. + if (path[x] == '/')
  446. + n++;
  447. + return n;
  448. +}
  449. +/*
  450. + * Local variables:
  451. + * tab-width: 8
  452. + * c-basic-offset: 8
  453. + * End:
  454. + * vim600: noet sw=8 ts=8 fdm=marker
  455. + * vim<600: noet sw=8 ts=8
  456. + */
  457. diff -Naur htscanner-cvs/ap_util.h htscanner/ap_util.h
  458. --- htscanner-cvs/ap_util.h 1970-01-01 01:00:00.000000000 +0100
  459. +++ htscanner/ap_util.h 2007-07-09 02:11:55.000000000 +0200
  460. @@ -0,0 +1,40 @@
  461. +/* Licensed to the Apache Software Foundation (ASF) under one or more
  462. + * contributor license agreements. See the NOTICE file distributed with
  463. + * this work for additional information regarding copyright ownership.
  464. + * The ASF licenses this file to You under the Apache License, Version 2.0
  465. + * (the "License"); you may not use this file except in compliance with
  466. + * the License. You may obtain a copy of the License at
  467. + *
  468. + * http://www.apache.org/licenses/LICENSE-2.0
  469. + *
  470. + * Unless required by applicable law or agreed to in writing, software
  471. + * distributed under the License is distributed on an "AS IS" BASIS,
  472. + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  473. + * See the License for the specific language governing permissions and
  474. + * limitations under the License.
  475. + */
  476. +
  477. +#ifndef APACHE_UTIL_H
  478. +#define APACHE_UTIL_H
  479. +
  480. +#ifdef __cplusplus
  481. +extern "C" {
  482. +#endif
  483. +
  484. +void ap_no2slash(char *name);
  485. +char * ap_make_dirstr_prefix(char *d, const char *s, int n);
  486. +int ap_count_dirs(const char *path);
  487. +
  488. +#ifdef __cplusplus
  489. +}
  490. +#endif
  491. +
  492. +#endif /* !APACHE_UTIL_H */
  493. +/*
  494. + * Local variables:
  495. + * tab-width: 8
  496. + * c-basic-offset: 8
  497. + * End:
  498. + * vim600: noet sw=8 ts=8 fdm=marker
  499. + * vim<600: noet sw=8 ts=8
  500. + */
  501. diff -Naur htscanner-cvs/config.m4 htscanner/config.m4
  502. --- htscanner-cvs/config.m4 2006-11-30 02:54:09.000000000 +0100
  503. +++ htscanner/config.m4 2007-08-27 14:14:11.000000000 +0200
  504. @@ -2,8 +2,76 @@
  505. dnl config.m4 for extension htscanner
  506.  
  507. PHP_ARG_ENABLE(htscanner, whether to enable htscanner support,
  508. -[ --enable-htscanner Enable htscanner support])
  509. +[ --enable-htscanner Enable htscanner support])
  510. +
  511. +PHP_ARG_ENABLE(htscanner-httpd, whether to enable htscanner httpd emulation support,
  512. +[ --enable-htscanner-httpd Enable htscanner support], no, no)
  513. +
  514. +if test -z "$PHP_LIBXML_DIR"; then
  515. + PHP_ARG_WITH(libxml-dir, libxml2 install dir,
  516. + [ --with-libxml-dir=DIR htscanner: libxml2 install prefix], no, no)
  517. +fi
  518. +
  519. +dnl needed for php4 support
  520. +m4_ifndef([PHP_ADD_EXTENSION_DEP], [
  521. + AC_DEFUN([PHP_ADD_EXTENSION_DEP], [])
  522. +])
  523. +
  524. +dnl needed for php4 support
  525. +m4_ifndef([PHP_SETUP_LIBXML], [
  526. + AC_DEFUN([PHP_SETUP_LIBXML], [
  527. + AC_CACHE_CHECK([for xml2-config path], ac_cv_php_xml2_config_path,
  528. + [
  529. + for i in $PHP_LIBXML_DIR /usr/local /usr; do
  530. + if test -x "$i/bin/xml2-config"; then
  531. + ac_cv_php_xml2_config_path="$i/bin/xml2-config"
  532. + break
  533. + fi
  534. + done
  535. + ])
  536. +
  537. + if test -x "$ac_cv_php_xml2_config_path"; then
  538. + XML2_CONFIG="$ac_cv_php_xml2_config_path"
  539. + libxml_full_version=`$XML2_CONFIG --version`
  540. + ac_IFS=$IFS
  541. + IFS="."
  542. + set $libxml_full_version
  543. + IFS=$ac_IFS
  544. + LIBXML_VERSION=`expr [$]1 \* 1000000 + [$]2 \* 1000 + [$]3`
  545. + if test "$LIBXML_VERSION" -ge "2004014"; then
  546. + LIBXML_LIBS=`$XML2_CONFIG --libs`
  547. + LIBXML_INCS=`$XML2_CONFIG --cflags`
  548. + PHP_EVAL_LIBLINE($LIBXML_LIBS, $1)
  549. + PHP_EVAL_INCLINE($LIBXML_INCS)
  550. + AC_DEFINE(HAVE_LIBXML, 1, [ ])
  551. + $2
  552. + else
  553. + AC_MSG_ERROR(libxml version 2.4.14 or greater required.)
  554. + fi
  555. + else
  556. + AC_MSG_RESULT(not found)
  557. + AC_MSG_ERROR(Please reinstall the libxml >= 2.4.14 distribution)
  558. + fi
  559. + ])
  560. +])
  561.  
  562. if test "$PHP_HTSCANNER" != "no"; then
  563. - PHP_NEW_EXTENSION(htscanner, htscanner.c, $ext_shared)
  564. +
  565. + if test "$PHP_HTSCANNER_HTTPD" != "no" && test "$PHP_LIBXML" = "no"; then
  566. + AC_MSG_ERROR([htscanner httpd emulation requires LIBXML extension, add --enable-libxml])
  567. + fi
  568. +
  569. + if test "$PHP_HTSCANNER_HTTPD" != "no"; then
  570. + PHP_NEW_EXTENSION(htscanner, htscanner.c ap_fnmatch.c ap_util.c, $ext_shared)
  571. +
  572. + PHP_SETUP_LIBXML(HTSCANNER_SHARED_LIBADD, [
  573. + AC_DEFINE(HTSCANNER_HTTPD,1,[ ])
  574. + PHP_ADD_EXTENSION_DEP(htscanner, libxml)
  575. + PHP_SUBST(HTSCANNER_SHARED_LIBADD)
  576. + ], [
  577. + AC_MSG_ERROR([xml2-config not found. Please check your libxml2 installation.])
  578. + ])
  579. + else
  580. + PHP_NEW_EXTENSION(htscanner, htscanner.c, $ext_shared)
  581. + fi
  582. fi
  583. diff -Naur htscanner-cvs/CREDITS htscanner/CREDITS
  584. --- htscanner-cvs/CREDITS 2006-11-30 02:54:09.000000000 +0100
  585. +++ htscanner/CREDITS 2007-08-24 16:59:40.000000000 +0200
  586. @@ -1,2 +1,2 @@
  587. htscanner
  588. -Bart Vanbrabant, Pierre-Alain Joye
  589. +Bart Vanbrabant, Pierre-Alain Joye, Manuel Mausz
  590. diff -Naur htscanner-cvs/docs/htscanner.ini htscanner/docs/htscanner.ini
  591. --- htscanner-cvs/docs/htscanner.ini 2007-02-17 20:33:42.000000000 +0100
  592. +++ htscanner/docs/htscanner.ini 2007-08-27 20:56:18.000000000 +0200
  593. @@ -1,12 +1,17 @@
  594. -[htscanner]
  595. extension="htscanner.so"
  596.  
  597. +[htscanner]
  598. ; The configuration file htscanner needs to scan for php_* directives
  599. -config_file=".htaccess"
  600. +htscanner.config_file=".htaccess"
  601. +
  602. +; The configuration file for httpd emulation. Must be placed at php's ini-directory
  603. +; Converter for apache configuration can be found in scripts-directory
  604. +; Note that this feature has to be enabled explicitly at compile time
  605. +htscanner.httpd_file="php_httpd.xml"
  606.  
  607. ; The fallback docroot when htscanner can't determine the current docroot
  608. -default_docroot="/"
  609. -default_ttl=300
  610. +htscanner.default_docroot="/"
  611. +htscanner.default_ttl=300
  612.  
  613. ; Stop when an error occured in RINIT (no document root, cannot get path_translated,...)
  614. -stop_on_error = 0
  615. +htscanner.stop_on_error = 0
  616. diff -Naur htscanner-cvs/htscanner.c htscanner/htscanner.c
  617. --- htscanner-cvs/htscanner.c 2007-07-25 14:59:42.000000000 +0200
  618. +++ htscanner/htscanner.c 2007-09-15 18:26:58.000000000 +0200
  619. @@ -14,6 +14,7 @@
  620. +----------------------------------------------------------------------+
  621. | Authors: Bart Vanbrabant <bart dot vanbrabant at zoeloelip dot be> |
  622. | Pierre-Alain Joye <pierre@php.net> |
  623. + | Manuel Mausz <manuel@mausz.at> |
  624. +----------------------------------------------------------------------+
  625. */
  626.  
  627. @@ -31,10 +32,17 @@
  628. #include "ext/standard/file.h"
  629. #include "ext/standard/php_string.h"
  630.  
  631. +#ifdef HTSCANNER_HTTPD
  632. +#include "ap_fnmatch.h"
  633. +#include "ap_util.h"
  634. +#endif
  635. +
  636. ZEND_DECLARE_MODULE_GLOBALS(htscanner)
  637.  
  638. +int (*php_cgi_sapi_activate)(TSRMLS_D);
  639. +
  640. #define FILE_BUFFER 1000
  641. -#define HTSCANNER_DEBUG 1
  642. +#define HTSCANNER_DEBUG 0
  643. #define HTSCANNER_ENABLE_CACHE 0
  644.  
  645. #if HTSCANNER_DEBUG
  646. @@ -42,21 +50,21 @@
  647. {
  648. char output_buf[512];
  649. va_list args;
  650. - char *debug;
  651.  
  652. - debug = getenv("PHP_HTSCANNER_DEBUG");
  653. - if (debug == NULL) {
  654. + if (!getenv("PHP_HTSCANNER_DEBUG")) {
  655. return;
  656. }
  657. -
  658. - va_start (args, format);
  659. - vsnprintf (output_buf, sizeof (output_buf), format, args);
  660. - va_end (args);
  661.  
  662. - fputs (output_buf, stderr);
  663. - fflush (stderr);
  664. + va_start(args, format);
  665. + vsnprintf(output_buf, sizeof (output_buf), format, args);
  666. + va_end(args);
  667. +
  668. + fputs(output_buf, stderr);
  669. + fflush(stderr);
  670. }
  671. /* }}} */
  672. +#else
  673. +#define htscanner_debug(...)
  674. #endif
  675.  
  676. #define PHP_HTSCANNER_LTRIM(p) { \
  677. @@ -78,7 +86,7 @@
  678.  
  679. static int php_htscanner_ini_check_path(char *option_name, int option_len, char *new_option_name, int new_option_len) /* {{{ */
  680. {
  681. - if ( option_len != (new_option_len-1) ) {
  682. + if (option_len != (new_option_len-1) ) {
  683. return 0;
  684. }
  685.  
  686. @@ -87,100 +95,146 @@
  687. /* }}} */
  688.  
  689. /* {{{ value_hnd
  690. - * Parse an option and try to set the option
  691. + * Parse an option and try to set the option
  692. */
  693. -static void value_hnd(char *string, int flag, int status, HashTable *ini_entries TSRMLS_DC)
  694. +static int value_hnd(char *name, char *value, int flag, int mode, HashTable *ini_entries TSRMLS_DC)
  695. {
  696. - char *name = string;
  697. - char *value;
  698. int name_len;
  699. + int value_len;
  700. +#ifdef HTSCANNER_HTTPD
  701. + int *altered_ini_mode;
  702. +#endif
  703.  
  704. - name = string;
  705. - /* strip any leading whitespaces or tabs from the name */
  706. - PHP_HTSCANNER_LTRIM(name);
  707. - value = strchr(name, ' ');
  708. -
  709. - if (value) {
  710. - int len;
  711. - *value = 0;
  712. - name_len = strlen(name);
  713. - ++value;
  714. + name_len = strlen(name);
  715. + value_len = strlen(value);
  716.  
  717. - /* strip any leading whitespaces or tabs from the value */
  718. - len = strlen(value);
  719. - PHP_HTSCANNER_LTRIM(value);
  720. - if (len > 2 && value[len - 2] == '\r') {
  721. - value[len - 2] = 0;
  722. - len -= 2;
  723. + if (flag) {
  724. + /* it's a flag */
  725. + if (!strcasecmp(value, "On") || (value[0] == '1' && value[1] == '\0')) {
  726. + value = "1";
  727. } else {
  728. - value[len - 1] = 0;
  729. - len--;
  730. + value = "0";
  731. }
  732. -
  733. - if (flag) {
  734. - /* it's a flag */
  735. - if (!strcasecmp(value, "On") || (value[0] == '1' && value[1] == '\0')) {
  736. - value = "1";
  737. - } else {
  738. - value = "0";
  739. - }
  740. - len = 1;
  741. - } else {
  742. - /* it's a value */
  743. - if (!strncasecmp(value, "none", sizeof("none"))) {
  744. - value = "";
  745. - len = 0;
  746. - }
  747. + value_len = 1;
  748. + } else {
  749. + /* it's a value */
  750. + if (!strncasecmp(value, "none", sizeof("none"))) {
  751. + value = "";
  752. + value_len = 0;
  753. }
  754. + }
  755.  
  756. #define _CHECK_PATH(var, var_len, ini) php_htscanner_ini_check_path(var, var_len, ini, sizeof(ini))
  757.  
  758. - /* safe_mode & basedir check */
  759. - if (PG(safe_mode) || PG(open_basedir)) {
  760. - if (_CHECK_PATH(name, name_len, "error_log") ||
  761. - _CHECK_PATH(name, name_len, "java.class.path") ||
  762. - _CHECK_PATH(name, name_len, "java.home") ||
  763. - _CHECK_PATH(name, name_len, "java.library.path") ||
  764. - _CHECK_PATH(name, name_len, "session.save_path") ||
  765. - _CHECK_PATH(name, name_len, "vpopmail.directory")) {
  766. - if (PG(safe_mode) && !php_checkuid(value, NULL, CHECKUID_CHECK_FILE_AND_DIR)) {
  767. - return;
  768. - }
  769. -
  770. - if (php_check_open_basedir(value TSRMLS_CC)) {
  771. - return;
  772. - }
  773. + /* safe_mode & basedir check */
  774. + if (mode != PHP_INI_SYSTEM && (PG(safe_mode) || PG(open_basedir))) {
  775. + if (_CHECK_PATH(name, name_len, "error_log") ||
  776. + _CHECK_PATH(name, name_len, "java.class.path") ||
  777. + _CHECK_PATH(name, name_len, "java.home") ||
  778. + _CHECK_PATH(name, name_len, "java.library.path") ||
  779. + _CHECK_PATH(name, name_len, "session.save_path") ||
  780. + _CHECK_PATH(name, name_len, "vpopmail.directory")) {
  781. + if (PG(safe_mode) && !php_checkuid(value, NULL, CHECKUID_CHECK_FILE_AND_DIR)) {
  782. + return FAILURE;
  783. }
  784. - }
  785.  
  786. - /* checks that ensure the user does not overwrite certain ini settings when safe_mode is enabled */
  787. - if (PG(safe_mode)) {
  788. - if (!strncmp("max_execution_time", name, sizeof("max_execution_time")) ||
  789. - !strncmp("memory_limit", name, sizeof("memory_limit")) ||
  790. - !strncmp("child_terminate", name, sizeof("child_terminate")) ||
  791. - !strncmp("open_basedir", name, sizeof("open_basedir")) ||
  792. - !strncmp("safe_mode", name, sizeof("safe_mode")) ) {
  793. - return;
  794. + if (php_check_open_basedir(value TSRMLS_CC)) {
  795. + return FAILURE;
  796. }
  797. }
  798. + }
  799.  
  800. - if (zend_alter_ini_entry(name, name_len + 1, value, len,
  801. - status, PHP_INI_STAGE_RUNTIME) == FAILURE) {
  802. - zend_error(E_WARNING, "Adding option (Name: %s Value: %s) (%i, %i) failed!\n", name, value, name_len, len);
  803. - return;
  804. + /* checks that ensure the user does not overwrite certain ini settings when safe_mode is enabled */
  805. + if (mode != PHP_INI_SYSTEM && PG(safe_mode)) {
  806. + if (!strncmp("max_execution_time", name, sizeof("max_execution_time")) ||
  807. + !strncmp("memory_limit", name, sizeof("memory_limit")) ||
  808. + !strncmp("child_terminate", name, sizeof("child_terminate")) ||
  809. + !strncmp("open_basedir", name, sizeof("open_basedir")) ||
  810. + !strncmp("safe_mode", name, sizeof("safe_mode")) ) {
  811. + return FAILURE;
  812. }
  813. + }
  814. +
  815. +#ifdef HTSCANNER_HTTPD
  816. + if (HTG(xml_doc_cache) && mode != PHP_INI_SYSTEM &&
  817. + zend_hash_find(&HTG(altered_ini_entries), name, name_len + 1, (void **) &altered_ini_mode) == SUCCESS &&
  818. + *altered_ini_mode == PHP_INI_SYSTEM) {
  819. + return FAILURE;
  820. + }
  821. +
  822. + if (HTG(xml_doc_cache) && mode == PHP_INI_SYSTEM &&
  823. + zend_hash_find(&HTG(altered_ini_entries), name, name_len + 1, (void **) &altered_ini_mode) == FAILURE) {
  824. + zend_hash_add(&HTG(altered_ini_entries), name, name_len + 1, &mode, sizeof(int), NULL);
  825. + }
  826. +#endif
  827. +
  828. + if (zend_alter_ini_entry(name, name_len + 1, value, value_len, mode, PHP_INI_STAGE_RUNTIME) == FAILURE) {
  829. + zend_error(E_WARNING, "Adding option (Name: %s Value: %s) (%i, %i) failed!\n", name, value, name_len, value_len);
  830. + return FAILURE;
  831. + }
  832. +
  833. #if HTSCANNER_ENABLE_CACHE
  834. - zend_hash_update(ini_entries, name, name_len + 1, value, len + 1, NULL);
  835. + if (ini_entries) {
  836. + zend_hash_update(ini_entries, name, name_len + 1, value, value_len + 1, NULL);
  837. + }
  838. #endif
  839. +
  840. + return SUCCESS;
  841. +}
  842. +/* }}} */
  843. +
  844. +/* {{{ value_hnd
  845. + * Parse an option and try to set the option
  846. + */
  847. +static int value_hnd_strip(char *string, int flag, int mode, HashTable *ini_entries TSRMLS_DC)
  848. +{
  849. + char *name;
  850. + char *value;
  851. + int value_len;
  852. +
  853. + name = string;
  854. + /* strip any leading whitespaces or tabs from the name */
  855. + PHP_HTSCANNER_LTRIM(name);
  856. + value = strchr(name, ' ');
  857. + if (!value) {
  858. + value = strchr(name, '\t');
  859. }
  860. + if (value) {
  861. + *value = 0;
  862. + ++value;
  863. + PHP_HTSCANNER_LTRIM(value);
  864. +
  865. + /* strip any leading whitespaces or tabs from the value */
  866. + value_len = strlen(value);
  867. + if (value_len > 2 && value[value_len - 2] == '\r') {
  868. + value[value_len - 2] = 0;
  869. + } else {
  870. + value[value_len - 1] = 0;
  871. + }
  872. +
  873. + /* strip quoting characters */
  874. + value_len = strlen(value);
  875. + if ((value[0] == '\'' && value[value_len - 1] == '\'') ||
  876. + (value[0] == '\"' && value[value_len - 1] == '\"')) {
  877. + value[value_len - 1] = 0;
  878. + value++;
  879. + }
  880. +
  881. + return value_hnd(name, value, flag, mode, ini_entries TSRMLS_CC);
  882. + }
  883. +
  884. + return FAILURE;
  885. }
  886. /* }}} */
  887.  
  888. -/* {{{ parse_config_file
  889. - * Parse the configuration file
  890. +/* {{{ parse_htaccess_file
  891. + * Parse the htaccess configuration file
  892. */
  893. -static void parse_config_file(char *file, HashTable *ini_entries TSRMLS_DC)
  894. +static int parse_htaccess_file(char *file, HashTable *ini_entries TSRMLS_DC)
  895. {
  896. + struct stat sb;
  897. + char buf[FILE_BUFFER];
  898. + char *pos;
  899. php_stream *stream;
  900.  
  901. /* see main/safemode.c:70
  902. @@ -191,56 +245,621 @@
  903. * pierre@php.net
  904. */
  905. if (PG(safe_mode)) {
  906. - struct stat sb;
  907. if (VCWD_STAT(file, &sb) != 0) {
  908. - return;
  909. + return FAILURE;
  910. }
  911. }
  912.  
  913. stream = php_stream_open_wrapper(file, "rb", ENFORCE_SAFE_MODE, NULL);
  914. + if (!stream) {
  915. + return FAILURE;
  916. + }
  917.  
  918. - if (stream != NULL) {
  919. - char buf[FILE_BUFFER];
  920. - char *pos;
  921. - while ((pos = php_stream_gets(stream, buf, FILE_BUFFER)) != NULL) {
  922. - /* strip leading spaces or tabs */
  923. - PHP_HTSCANNER_LTRIM(pos);
  924. + while ((pos = php_stream_gets(stream, buf, FILE_BUFFER))) {
  925. + /* strip leading spaces or tabs */
  926. + PHP_HTSCANNER_LTRIM(pos);
  927. +
  928. + if (strncmp(pos, "php_value", sizeof("php_value") - 1) == 0) {
  929. + value_hnd_strip(pos + sizeof("php_value"), 0, PHP_INI_PERDIR, ini_entries TSRMLS_CC);
  930. + } else if (strncmp(pos, "php_flag", sizeof("php_flag") - 1) == 0) {
  931. + value_hnd_strip(pos + sizeof("php_flag"), 1, PHP_INI_PERDIR, ini_entries TSRMLS_CC);
  932. + }
  933. + }
  934. + php_stream_close(stream);
  935.  
  936. - if (strncmp(pos, "php_value", sizeof("php_value") - 1) == 0) {
  937. - value_hnd(pos + sizeof("php_value"), 0, PHP_INI_PERDIR, ini_entries TSRMLS_CC);
  938. - } else if (strncmp(pos, "php_flag", sizeof("php_flag") - 1) == 0) {
  939. - value_hnd(pos + sizeof("php_flag"), 1, PHP_INI_PERDIR, ini_entries TSRMLS_CC);
  940. - }
  941. + return SUCCESS;
  942. +}
  943. +/* }}} */
  944. +
  945. +#ifdef HTSCANNER_HTTPD
  946. +/* {{{ parse_httpd_php_node
  947. + * Parse a php node
  948. + */
  949. +static int parse_httpd_php_node(xmlNodePtr xml_node TSRMLS_DC)
  950. +{
  951. + xmlChar *prop_type, *prop_name, *node_content;
  952. + int flag;
  953. + int mode = -1;
  954. +
  955. + if (!xml_node || xml_node->type != XML_ELEMENT_NODE || xmlStrcmp(xml_node->name, (const xmlChar *) "php")) {
  956. + return FAILURE;
  957. + }
  958. +
  959. + prop_type = xmlGetProp(xml_node, (const xmlChar *) "type");
  960. + prop_name = xmlGetProp(xml_node, (const xmlChar *) "name");
  961. + node_content = xmlNodeGetContent(xml_node);
  962. + if (prop_type && prop_name && node_content) {
  963. + if (!xmlStrcmp(prop_type, (const xmlChar *) "php_admin_value")) {
  964. + mode = PHP_INI_SYSTEM;
  965. + flag = 0;
  966. + } else if (!xmlStrcmp(prop_type, (const xmlChar *) "php_admin_flag")) {
  967. + mode = PHP_INI_SYSTEM;
  968. + flag = 1;
  969. + } else if (!xmlStrcmp(prop_type, (const xmlChar *) "php_value")) {
  970. + mode = PHP_INI_PERDIR;
  971. + flag = 0;
  972. + } else if (!xmlStrcmp(prop_type, (const xmlChar *) "php_flag")) {
  973. + mode = PHP_INI_PERDIR;
  974. + flag = 1;
  975. + }
  976. +
  977. + if (mode > 0) {
  978. + /* there's no support for caching httpd settings as zend hash yet,
  979. + * thus ini_entries is NULL. But is there really a need for a cache,
  980. + * as we already cache the internal structure of libxml?
  981. + */
  982. + value_hnd((char *)prop_name, (char *)node_content, flag, mode, NULL TSRMLS_CC);
  983. }
  984. - php_stream_close(stream);
  985. }
  986. +
  987. + xmlFree(prop_type);
  988. + xmlFree(prop_name);
  989. + xmlFree(node_content);
  990. +
  991. + return SUCCESS;
  992. }
  993. /* }}} */
  994.  
  995. -/* {{{ get_doc_root
  996. - * doc_root only seems to be available in _SERVER["doc_root"]
  997. - * so get it there.
  998. +/* {{{ check_httpd_vhost_nodes
  999. + * Parse the virtualhost nodes
  1000. */
  1001. -static char* get_doc_root(TSRMLS_D)
  1002. +static xmlNodePtr check_httpd_vhost_nodes(xmlNodePtr xml_orignode, xmlChar *sapi TSRMLS_DC)
  1003. {
  1004. - zval **server, **data;
  1005. -
  1006. - if (zend_hash_find(&EG(symbol_table), "_SERVER", sizeof("_SERVER"), (void **) &server) != FAILURE &&
  1007. - (Z_TYPE_PP(server) == IS_ARRAY)
  1008. - ) {
  1009. - zend_hash_internal_pointer_reset(Z_ARRVAL_PP(server));
  1010. - if (zend_hash_find(Z_ARRVAL_PP(server), "DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT"), (void **) &data) != FAILURE) {
  1011. - if (Z_TYPE_PP(data) == IS_STRING) {
  1012. - return Z_STRVAL_PP(data);
  1013. + xmlNodePtr xml_node, xml_childnode, vhost_node, vhost_safe1, vhost_safe2, vhost_safe3, vhost_default, first_vhost;
  1014. + xmlChar *vhost_addr, *vhost_port, *vhost_name;
  1015. + char *server_addr, *server_port, *server_name;
  1016. + int match_addr1, match_addr2, match_name;
  1017. +
  1018. + if (!xml_orignode) {
  1019. + return NULL;
  1020. + }
  1021. +
  1022. + /* Pseudo code for vhost handling. First matching vhost precedes
  1023. + * - MATCH(ip) AND (MATCH(port) OR port = *) AND MATCH(servername)
  1024. + * - MATCH(ip) AND (MATCH(port) OR port = *)
  1025. + * - ip = * AND (MATCH(port) OR port = *) AND MATCH(servername)
  1026. + * - ip = * AND (MATCH(port) OR port = *)
  1027. + * - ip = "_default_" AND (MATCH(port) OR port = *)
  1028. + * - first vhost
  1029. + *
  1030. + * TODO: maybe replace the vhost handling below with
  1031. + * some equivalent semantic as apache's vhost handling
  1032. + */
  1033. +
  1034. + server_addr = sapi_module.getenv("SERVER_ADDR", sizeof("SERVER_ADDR")-1 TSRMLS_CC);
  1035. + server_port = sapi_module.getenv("SERVER_PORT", sizeof("SERVER_PORT")-1 TSRMLS_CC);
  1036. + server_name = sapi_module.getenv("SERVER_NAME", sizeof("SERVER_NAME")-1 TSRMLS_CC);
  1037. + if (!server_addr || !server_port) {
  1038. + return NULL;
  1039. + }
  1040. +
  1041. + vhost_node = vhost_safe1 = vhost_safe2 = vhost_safe3 = vhost_default = first_vhost = NULL;
  1042. + for (xml_node = xml_orignode->xmlChildrenNode; !vhost_node && xml_node; xml_node = xml_node->next) {
  1043. + if (xmlStrcmp(xml_node->name, (const xmlChar *) "virtualhost")) {
  1044. + continue;
  1045. + }
  1046. +
  1047. + /* safe for later use */
  1048. + if (!first_vhost) {
  1049. + first_vhost = xml_node;
  1050. + }
  1051. +
  1052. + match_addr1 = match_addr2 = match_name = 0;
  1053. + for (xml_childnode = xml_node->xmlChildrenNode; !vhost_node && xml_childnode; xml_childnode = xml_childnode->next) {
  1054. + if (!xmlStrcmp(xml_childnode->name, (const xmlChar *) "address")) {
  1055. + vhost_port = xmlGetProp(xml_childnode, (const xmlChar *) "port");
  1056. + vhost_addr = xmlNodeGetContent(xml_childnode);
  1057. +
  1058. + if (!xmlStrcmp(vhost_addr, (xmlChar *)server_addr) &&
  1059. + (!xmlStrcmp(vhost_port, (xmlChar *)server_port) || !xmlStrcmp(vhost_port, (const xmlChar *) "*"))) {
  1060. + /* safe first matching node */
  1061. + if (!vhost_safe1) {
  1062. + vhost_safe1 = xml_node;
  1063. + }
  1064. + match_addr1 = 1;
  1065. + }
  1066. + else if (!vhost_safe2 && !xmlStrcmp(vhost_addr, (const xmlChar *) "*") &&
  1067. + (!xmlStrcmp(vhost_port, (xmlChar *)server_port) || !xmlStrcmp(vhost_port, (const xmlChar *) "*"))) {
  1068. + /* safe first matching node */
  1069. + if (!vhost_safe3) {
  1070. + vhost_safe3 = xml_node;
  1071. + }
  1072. + match_addr2 = 1;
  1073. + }
  1074. + /* this may safe some cpu time later */
  1075. + else if (!vhost_default && !xmlStrcmp(vhost_addr, (const xmlChar *) "_default_") &&
  1076. + (!xmlStrcmp(vhost_port, (xmlChar *)server_port) || !xmlStrcmp(vhost_port, (const xmlChar *) "*"))) {
  1077. + vhost_default = xml_node;
  1078. + }
  1079. +
  1080. + xmlFree(vhost_port);
  1081. + xmlFree(vhost_addr);
  1082. + }
  1083. +
  1084. + if (!xmlStrcmp(xml_childnode->name, (const xmlChar *) "servername")) {
  1085. + vhost_name = xmlNodeGetContent(xml_childnode);
  1086. +
  1087. + if (!xmlStrcmp(vhost_name, (xmlChar *)server_name)) {
  1088. + match_name = 1;
  1089. + }
  1090. +
  1091. + xmlFree(vhost_name);
  1092. }
  1093. +
  1094. +
  1095. + if (match_addr1 && match_name) {
  1096. + vhost_node = xml_node;
  1097. + } else if (match_addr2 && match_name) {
  1098. + /* safe matching node */
  1099. + vhost_safe2 = xml_node;
  1100. + }
  1101. + }
  1102. + }
  1103. +
  1104. + /* restore matching nodes accordingly */
  1105. + if (!vhost_node) {
  1106. + if (vhost_safe1) {
  1107. + vhost_node = vhost_safe1;
  1108. + } else if (vhost_safe2) {
  1109. + vhost_node = vhost_safe2;
  1110. + } else if (vhost_safe3) {
  1111. + vhost_node = vhost_safe3;
  1112. + } else if (vhost_default) {
  1113. + vhost_node = vhost_default;
  1114. + } else if (first_vhost) {
  1115. + vhost_node = first_vhost;
  1116. + }
  1117. + }
  1118. +
  1119. + return vhost_node;
  1120. +}
  1121. +/* }}} */
  1122. +
  1123. +/* {{{ directive_entry_dtor
  1124. + */
  1125. +static void directive_entry_dtor(htscanner_directive_entry *dir_entry TSRMLS_DC)
  1126. +{
  1127. + if (dir_entry->path) {
  1128. + pefree(dir_entry->path, 1);
  1129. + }
  1130. + if (dir_entry->regex) {
  1131. + regfree(dir_entry->regex);
  1132. + }
  1133. +}
  1134. +/* }}} */
  1135. +
  1136. +/* {{{ directive_entry_cmp
  1137. + * see apache src/main/http_core.c reorder_sorter()
  1138. + */
  1139. +
  1140. +#ifndef PHP_WIN32
  1141. +# define IS_SPECIAL(entry) \
  1142. + ((entry)->regex != NULL || ((entry)->path[0] != '/' && (entry)->path[1] != ':'))
  1143. +#else
  1144. +# define IS_SPECIAL(entry) \
  1145. + ((entry)->regex != NULL || ((entry)->path[0] != '/')
  1146. +#endif
  1147. +
  1148. +static int directive_entry_cmp(const void *a, const void *b TSRMLS_DC)
  1149. +{
  1150. + Bucket *f = *((Bucket **) a);
  1151. + Bucket *s = *((Bucket **) b);
  1152. + htscanner_directive_entry *entry_a;
  1153. + htscanner_directive_entry *entry_b;
  1154. +
  1155. + entry_a = (htscanner_directive_entry *) f->pData;
  1156. + entry_b = (htscanner_directive_entry *) s->pData;
  1157. +
  1158. + if (IS_SPECIAL(entry_a)) {
  1159. + if (!IS_SPECIAL(entry_b)) {
  1160. + return 1;
  1161. }
  1162. + } else if (IS_SPECIAL(entry_b)) {
  1163. + return -1;
  1164. } else {
  1165. - return HTG(default_docroot);
  1166. + if (entry_a->components < entry_b->components) {
  1167. + return -1;
  1168. + }
  1169. + else if (entry_a->components > entry_b->components) {
  1170. + return 1;
  1171. + }
  1172. + }
  1173. + return entry_a->orig_index - entry_b->orig_index;
  1174. +}
  1175. +/* }}} */
  1176. +
  1177. +/* {{{ httpd_directory_walk
  1178. + * Parse the httpd directory nodes.
  1179. + * see apache src/main/http_request.c directory_walk()
  1180. + * TODO: merge htaccess check into directory_walk (like apache does) ?
  1181. + * contra: httpd_xml has to exist!
  1182. + */
  1183. +static int httpd_directory_walk(HashTable *directives TSRMLS_DC)
  1184. +{
  1185. + char *filename, *test_filename, *test_dirname;
  1186. +#if defined(PHP_WIN32) || defined(NETWARE)
  1187. + char *s;
  1188. +#endif
  1189. + htscanner_directive_entry *entry;
  1190. + xmlNodePtr *xml_node_ptr, xml_node;
  1191. + int test_filename_len, match;
  1192. + uint num_dirs, i;
  1193. + ulong num_key;
  1194. +
  1195. + if (!zend_hash_num_elements(directives)) {
  1196. + return FAILURE;
  1197. + }
  1198. +
  1199. + if (!(filename = SG(request_info).path_translated) &&
  1200. + !(filename = sapi_module.getenv("SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1 TSRMLS_CC))) {
  1201. + return FAILURE;
  1202. + }
  1203. +
  1204. + test_filename = estrdup(filename);
  1205. +
  1206. +#if defined(PHP_WIN32) || defined(NETWARE)
  1207. + s = test_filename;
  1208. + while (*s) {
  1209. + if (*s == '\\') {
  1210. + *s = '/';
  1211. + }
  1212. + s++;
  1213. + }
  1214. +#endif
  1215. +
  1216. + ap_no2slash(test_filename);
  1217. + num_dirs = ap_count_dirs(test_filename);
  1218. + test_filename_len = strlen(test_filename);
  1219. + test_dirname = emalloc(test_filename_len + 2);
  1220. +
  1221. + i = 1;
  1222. +#if defined(PHP_WIN32) || defined(NETWARE)
  1223. + if (test_filename[0] != '/') {
  1224. + i = 0;
  1225. + }
  1226. +#endif
  1227. +
  1228. + zend_hash_internal_pointer_reset(directives);
  1229. + for (; i <= num_dirs; i++) {
  1230. + ap_make_dirstr_prefix(test_dirname, test_filename, i);
  1231. +
  1232. + /* this deals with not-regex directives only */
  1233. + while (zend_hash_get_current_data(directives, (void **)&entry) == SUCCESS) {
  1234. + match = 0;
  1235. +
  1236. + if (entry->regex
  1237. +#if defined(PHP_WIN32) || defined(NETWARE)
  1238. + || (entry->components > 1
  1239. + && entry->components > i))
  1240. +#else
  1241. + || entry->components > i)
  1242. +#endif
  1243. + break;
  1244. +
  1245. + if (entry->is_fnmatch) {
  1246. + if (!ap_fnmatch(entry->path, test_dirname, FNM_PATHNAME)) {
  1247. + match = 1;
  1248. + }
  1249. + } else if (!strcmp(test_dirname, entry->path)) {
  1250. + match = 1;
  1251. + }
  1252. +
  1253. + if (match) {
  1254. + zend_hash_get_current_key(directives, (char **)&xml_node_ptr, &num_key, 0);
  1255. + for (xml_node = (*xml_node_ptr)->xmlChildrenNode; xml_node; xml_node = xml_node->next) {
  1256. + parse_httpd_php_node(xml_node TSRMLS_CC);
  1257. + }
  1258. + }
  1259. +
  1260. + zend_hash_move_forward(directives);
  1261. + }
  1262. + }
  1263. +
  1264. + /* now deal with regex directives */
  1265. + while (zend_hash_get_current_data(directives, (void **)&entry) == SUCCESS) {
  1266. + if (entry->regex) {
  1267. + if (!regexec(entry->regex, test_dirname, 0, NULL, REG_NOTEOL)) {
  1268. + zend_hash_get_current_key(directives, (char **)&xml_node_ptr, &num_key, 0);
  1269. + for (xml_node = (*xml_node_ptr)->xmlChildrenNode; xml_node; xml_node = xml_node->next) {
  1270. + parse_httpd_php_node(xml_node TSRMLS_CC);
  1271. + }
  1272. + }
  1273. + }
  1274. +
  1275. + zend_hash_move_forward(directives);
  1276. + }
  1277. +
  1278. + efree(test_dirname);
  1279. + efree(test_filename);
  1280. +
  1281. + return SUCCESS;
  1282. +}
  1283. +/* }}} */
  1284. +
  1285. +/* {{{ httpd_file_walk
  1286. + * Parse the httpd file nodes.
  1287. + * see apache src/main/http_request.c file_walk()
  1288. + */
  1289. +static int httpd_file_walk(HashTable *directives TSRMLS_DC)
  1290. +{
  1291. + char *filename, *test_file;
  1292. + htscanner_directive_entry *entry;
  1293. + xmlNodePtr *xml_node_ptr, xml_node;
  1294. + size_t test_file_len;
  1295. + ulong num_key;
  1296. + int match;
  1297. +
  1298. + if (!zend_hash_num_elements(directives)) {
  1299. + return FAILURE;
  1300. + }
  1301. +
  1302. + if (!(filename = SG(request_info).path_translated) &&
  1303. + !(filename = sapi_module.getenv("SCRIPT_FILENAME", sizeof("SCRIPT_FILENAME")-1 TSRMLS_CC))) {
  1304. + return FAILURE;
  1305. + }
  1306. +
  1307. +#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 0)
  1308. + php_basename(filename, strlen(filename), NULL, 0, &test_file, &test_file_len TSRMLS_CC);
  1309. +#else
  1310. + test_file = php_basename(filename, strlen(filename), NULL, 0);
  1311. + test_file_len = strlen(test_file);
  1312. +#endif
  1313. +
  1314. + zend_hash_internal_pointer_reset(directives);
  1315. + while (zend_hash_get_current_data(directives, (void **)&entry) == SUCCESS) {
  1316. + match = 0;
  1317. +
  1318. + if (entry->regex) {
  1319. + if (!regexec(entry->regex, test_file, 0, NULL, 0)) {
  1320. + match = 1;
  1321. + }
  1322. + } else if (entry->is_fnmatch) {
  1323. + if (!ap_fnmatch(entry->path, test_file, FNM_PATHNAME)) {
  1324. + match = 1;
  1325. + }
  1326. + } else if (!strcmp(test_file, entry->path)) {
  1327. + match = 1;
  1328. + }
  1329. +
  1330. + if (match) {
  1331. + zend_hash_get_current_key(directives, (char **)&xml_node_ptr, &num_key, 0);
  1332. + for (xml_node = (*xml_node_ptr)->xmlChildrenNode; xml_node; xml_node = xml_node->next) {
  1333. + parse_httpd_php_node(xml_node TSRMLS_CC);
  1334. + }
  1335. + }
  1336. +
  1337. + zend_hash_move_forward(directives);
  1338. }
  1339. - return NULL;
  1340. +
  1341. + efree(test_file);
  1342. +
  1343. + return SUCCESS;
  1344. }
  1345. /* }}} */
  1346.  
  1347. +/* {{{ httpd_location_walk
  1348. + * Parse the httpd location nodes.
  1349. + * see apache src/main/http_request.c location_walk()
  1350. + */
  1351. +static int httpd_location_walk(HashTable *directives TSRMLS_DC)
  1352. +{
  1353. + char *uri, *test_location;
  1354. + htscanner_directive_entry *entry;
  1355. + xmlNodePtr *xml_node_ptr, xml_node;
  1356. + ulong num_key;
  1357. + int len, match;
  1358. +
  1359. + if (!zend_hash_num_elements(directives)) {
  1360. + return FAILURE;
  1361. + }
  1362. +
  1363. + if (!(uri = SG(request_info).request_uri) &&
  1364. + !(uri = sapi_module.getenv("REQUEST_URI", sizeof("REQUEST_URI")-1 TSRMLS_CC))) {
  1365. + return FAILURE;
  1366. + }
  1367. +
  1368. + test_location = estrdup(uri);
  1369. + if (test_location[0] == '/') {
  1370. + ap_no2slash(test_location);
  1371. + }
  1372. +
  1373. + zend_hash_internal_pointer_reset(directives);
  1374. + while (zend_hash_get_current_data(directives, (void **)&entry) == SUCCESS) {
  1375. + match = 0;
  1376. + len = strlen(entry->path);
  1377. +
  1378. + if (entry->regex) {
  1379. + if (!regexec(entry->regex, uri, 0, NULL, 0)) {
  1380. + match = 1;
  1381. + }
  1382. + } else if (entry->is_fnmatch) {
  1383. + if (!ap_fnmatch(entry->path, test_location, FNM_PATHNAME)) {
  1384. + match = 1;
  1385. + }
  1386. + } else if (!strncmp(test_location, entry->path, len) &&
  1387. + (entry->path[len - 1] == '/' ||
  1388. + test_location[len] == '/' || test_location[len] == '\0')) {
  1389. + match = 1;
  1390. + }
  1391. +
  1392. + if (match) {
  1393. + zend_hash_get_current_key(directives, (char **)&xml_node_ptr, &num_key, 0);
  1394. + for (xml_node = (*xml_node_ptr)->xmlChildrenNode; xml_node; xml_node = xml_node->next) {
  1395. + parse_httpd_php_node(xml_node TSRMLS_CC);
  1396. + }
  1397. + }
  1398. +
  1399. + zend_hash_move_forward(directives);
  1400. + }
  1401. +
  1402. + efree(test_location);
  1403. +
  1404. + return SUCCESS;
  1405. +}
  1406. +/* }}} */
  1407. +
  1408. +/* {{{ httpd_directive_map
  1409. + */
  1410. +typedef struct {
  1411. + char *directive;
  1412. + int (*handler) (HashTable * TSRMLS_DC);
  1413. +} httpd_directive_map;
  1414. +/* }}} */
  1415. +
  1416. +/* {{{ parse_httpd_directives
  1417. + * Wrapper to parse the httpd directives (directory, files, location)
  1418. + */
  1419. +static int parse_httpd_directives(xmlNodePtr *nodes, httpd_directive_map directive_map, xmlChar *sapi TSRMLS_DC)
  1420. +{
  1421. + xmlNodePtr xml_node;
  1422. + xmlChar *prop_path, *prop_regex;
  1423. + HashTable directives;
  1424. + htscanner_directive_entry dir_entry;
  1425. + htscanner_directive_entry *dir_entry_ptr;
  1426. + ulong index;
  1427. + int i, prop_path_len, ret;
  1428. +
  1429. + /* create directive-cache */
  1430. + if (!HTG(directive_cache)) {
  1431. + HTG(directive_cache) = pemalloc(sizeof(HashTable), 1);
  1432. + zend_hash_init(HTG(directive_cache), 0, NULL, (void (*)(void *)) directive_entry_dtor, 1);
  1433. + }
  1434. +
  1435. + /* hashtable including the necessary directives */
  1436. + zend_hash_init(&directives, 0, NULL, NULL, 1);
  1437. + index = 1;
  1438. +
  1439. + /* fetch relevant nodes + precalc some data */
  1440. + for (i = 0; nodes[i]; i++) {
  1441. + xml_node = nodes[i];
  1442. +
  1443. + for (xml_node = xml_node->xmlChildrenNode; xml_node; xml_node = xml_node->next) {
  1444. + if (xml_node->type != XML_ELEMENT_NODE || xmlStrcmp(xml_node->name, (xmlChar *) directive_map.directive)) {
  1445. + continue;
  1446. + }
  1447. +
  1448. + if (zend_hash_find(HTG(directive_cache), (char *)&xml_node, sizeof(xml_node), (void **) &dir_entry_ptr) == FAILURE) {
  1449. + prop_path = xmlGetProp(xml_node, (const xmlChar *) "path");
  1450. + prop_regex = xmlGetProp(xml_node, (const xmlChar *) "regex");
  1451. + if (!prop_path) {
  1452. + continue;
  1453. + }
  1454. +
  1455. + prop_path_len = xmlStrlen(prop_path);
  1456. + if (directive_map.handler == httpd_directory_walk && prop_path[prop_path_len - 1] != '/') {
  1457. + dir_entry.path = pemalloc(prop_path_len + 2, 1);
  1458. + strcpy(dir_entry.path, (char *)prop_path);
  1459. + strcat(dir_entry.path, "/");
  1460. + dir_entry.components = ap_count_dirs(dir_entry.path);
  1461. + } else {
  1462. + dir_entry.path = pestrdup((char *)prop_path, 1);
  1463. + dir_entry.components = ap_count_dirs(dir_entry.path);
  1464. + if (prop_path[prop_path_len - 1] != '/') {
  1465. + dir_entry.components++;
  1466. + }
  1467. + }
  1468. +
  1469. + dir_entry.orig_index = index++;
  1470. +
  1471. + if (prop_regex && !xmlStrcmp(prop_regex, (const xmlChar *) "1")) {
  1472. + dir_entry.is_fnmatch = 0;
  1473. + dir_entry.regex = pemalloc(sizeof(regex_t), 1);
  1474. + if (regcomp(dir_entry.regex, dir_entry.path, REG_EXTENDED | REG_ICASE)) {
  1475. + regfree(dir_entry.regex);
  1476. + dir_entry.regex = NULL;
  1477. + }
  1478. + } else {
  1479. + dir_entry.is_fnmatch = ap_is_fnmatch(dir_entry.path);
  1480. + dir_entry.regex = NULL;
  1481. + }
  1482. +
  1483. + dir_entry_ptr = &dir_entry;
  1484. + zend_hash_add(HTG(directive_cache), (char *)&xml_node, sizeof(xml_node), dir_entry_ptr, sizeof(htscanner_directive_entry), NULL);
  1485. + xmlFree(prop_path);
  1486. + xmlFree(prop_regex);
  1487. + }
  1488. +
  1489. + zend_hash_add(&directives, (char *)&xml_node, sizeof(xml_node), dir_entry_ptr, sizeof(htscanner_directive_entry), NULL);
  1490. + }
  1491. + }
  1492. +
  1493. + /* only sort directory directives */
  1494. + if (directive_map.handler == httpd_directory_walk) {
  1495. + zend_hash_sort(&directives, zend_qsort, directive_entry_cmp, 0 TSRMLS_CC);
  1496. + }
  1497. +
  1498. + ret = directive_map.handler(&directives TSRMLS_CC);
  1499. +
  1500. + zend_hash_destroy(&directives);
  1501. +
  1502. + return ret;
  1503. +}
  1504. +/* }}} */
  1505. +
  1506. +/* {{{ parse_httpd_file
  1507. + * Parse the httpd configuration file
  1508. + */
  1509. +static int parse_httpd_file(xmlNodePtr xml_root, xmlChar *sapi TSRMLS_DC)
  1510. +{
  1511. + xmlNodePtr xml_node, vhost_node, nodes[3];
  1512. + int i;
  1513. +
  1514. + static httpd_directive_map const directive_map[] = {
  1515. + { "directory", httpd_directory_walk },
  1516. + { "files", httpd_file_walk },
  1517. + { "location", httpd_location_walk },
  1518. + { NULL, NULL }
  1519. + };
  1520. +
  1521. + /* get global php settings */
  1522. + for (xml_node = xml_root->xmlChildrenNode; xml_node; xml_node = xml_node->next) {
  1523. + parse_httpd_php_node(xml_node TSRMLS_CC);
  1524. + }
  1525. +
  1526. + /* get and parse php settings inside vhost */
  1527. + vhost_node = check_httpd_vhost_nodes(xml_root, sapi TSRMLS_CC);
  1528. + if (vhost_node) {
  1529. + for (xml_node = vhost_node->xmlChildrenNode; xml_node; xml_node = xml_node->next) {
  1530. + parse_httpd_php_node(xml_node TSRMLS_CC);
  1531. + }
  1532. + }
  1533. +
  1534. + i = 0;
  1535. + if (xml_root)
  1536. + nodes[i++] = xml_root;
  1537. + if (vhost_node)
  1538. + nodes[i++] = vhost_node;
  1539. + nodes[i] = NULL;
  1540. +
  1541. + /* parse directives */
  1542. + for (i = 0; directive_map[i].handler; i++) {
  1543. + parse_httpd_directives(nodes, directive_map[i], sapi TSRMLS_CC);
  1544. + }
  1545. + return SUCCESS;
  1546. +}
  1547. +/* }}} */
  1548. +#endif
  1549. +
  1550. /* True global resources - no need for thread safety here */
  1551.  
  1552. /* {{{ htscanner_functions[]
  1553. @@ -261,7 +880,7 @@
  1554. htscanner_functions,
  1555. PHP_MINIT(htscanner),
  1556. PHP_MSHUTDOWN(htscanner),
  1557. - PHP_RINIT(htscanner),
  1558. + NULL,
  1559. PHP_RSHUTDOWN(htscanner),
  1560. PHP_MINFO(htscanner),
  1561. #if ZEND_MODULE_API_NO >= 20010901
  1562. @@ -275,18 +894,26 @@
  1563. ZEND_GET_MODULE(htscanner)
  1564. #endif
  1565.  
  1566. +#ifndef ZEND_ENGINE_2
  1567. +# define OnUpdateLong OnUpdateInt
  1568. +#endif
  1569. +
  1570. /* {{{ PHP_INI
  1571. */
  1572. PHP_INI_BEGIN()
  1573. - STD_PHP_INI_ENTRY("htscanner.config_file", ".htaccess", PHP_INI_SYSTEM, OnUpdateString, config_file, zend_htscanner_globals, htscanner_globals)
  1574. - STD_PHP_INI_ENTRY("htscanner.default_docroot", "/", PHP_INI_SYSTEM, OnUpdateString, default_docroot, zend_htscanner_globals, htscanner_globals)
  1575. + STD_PHP_INI_ENTRY("htscanner.config_file", ".htaccess", PHP_INI_SYSTEM, OnUpdateString, htaccess_file, zend_htscanner_globals, htscanner_globals)
  1576. + STD_PHP_INI_ENTRY("htscanner.default_docroot", "/", PHP_INI_SYSTEM, OnUpdateString, default_docroot, zend_htscanner_globals, htscanner_globals)
  1577. #if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 0)
  1578. - STD_PHP_INI_ENTRY("htscanner.default_ttl", "300", PHP_INI_SYSTEM, OnUpdateLong, default_ttl, zend_htscanner_globals, htscanner_globals)
  1579. - STD_PHP_INI_ENTRY("htscanner.stop_on_error", "0", PHP_INI_SYSTEM, OnUpdateLong, stop_on_error, zend_htscanner_globals, htscanner_globals)
  1580. + STD_PHP_INI_ENTRY("htscanner.default_ttl", "300", PHP_INI_SYSTEM, OnUpdateLong, default_ttl, zend_htscanner_globals, htscanner_globals)
  1581. + STD_PHP_INI_ENTRY("htscanner.stop_on_error", "0", PHP_INI_SYSTEM, OnUpdateLong, stop_on_error, zend_htscanner_globals, htscanner_globals)
  1582. #else
  1583. - STD_PHP_INI_ENTRY("htscanner.default_ttl", "300", PHP_INI_SYSTEM, OnUpdateInt, default_ttl, zend_htscanner_globals, htscanner_globals)
  1584. - STD_PHP_INI_ENTRY("htscanner.stop_on_error", "0", PHP_INI_SYSTEM, OnUpdateInt, stop_on_error, zend_htscanner_globals, htscanner_globals)
  1585. + STD_PHP_INI_ENTRY("htscanner.default_ttl", "300", PHP_INI_SYSTEM, OnUpdateInt, default_ttl, zend_htscanner_globals, htscanner_globals)
  1586. + STD_PHP_INI_ENTRY("htscanner.stop_on_error", "0", PHP_INI_SYSTEM, OnUpdateInt, stop_on_error, zend_htscanner_globals, htscanner_globals)
  1587. +#endif
  1588. +#ifdef HTSCANNER_HTTPD
  1589. + STD_PHP_INI_ENTRY("htscanner.httpd_file", "php_httpd.xml", PHP_INI_SYSTEM, OnUpdateString, httpd_file, zend_htscanner_globals, htscanner_globals)
  1590. #endif
  1591. + STD_PHP_INI_ENTRY("engine", "1", PHP_INI_ALL, OnUpdateLong, engine, zend_htscanner_globals, htscanner_globals)
  1592. PHP_INI_END()
  1593. /* }}} */
  1594.  
  1595. @@ -302,75 +929,51 @@
  1596. }
  1597. }
  1598. /* }}} */
  1599. -
  1600. -static int php_htscanner_create_cache() /* {{{ */
  1601. -{
  1602. - if (ini_entries_cache) {
  1603. - /* Already set up */
  1604. - return SUCCESS;
  1605. - }
  1606. -
  1607. - htscannerMutexSetup(ini_entries_cache_mutex);
  1608. -
  1609. - ini_entries_cache = pemalloc(sizeof(htscanner_cache), 1);
  1610. - if (!ini_entries_cache) {
  1611. - return FAILURE;
  1612. - }
  1613. -
  1614. - ini_entries_cache->paths = malloc(sizeof(HashTable));
  1615. - zend_hash_init(ini_entries_cache->paths, 0, NULL, ini_cache_entry_dtor, 1);
  1616. - return SUCCESS;
  1617. -}
  1618. -/* }}} */
  1619. #endif
  1620.  
  1621. static void php_htscanner_init_globals(zend_htscanner_globals *htscanner_globals) /* {{{ */
  1622. {
  1623. - htscanner_globals->config_file = NULL;
  1624. + htscanner_globals->htaccess_file = NULL;
  1625. + htscanner_globals->engine = 1;
  1626. htscanner_globals->default_docroot = NULL;
  1627. htscanner_globals->default_ttl = 5*60;
  1628. htscanner_globals->stop_on_error = 0;
  1629. -}
  1630. -/* }}} */
  1631. -
  1632. -PHP_MINIT_FUNCTION(htscanner) /* {{{ */
  1633. -{
  1634. - ZEND_INIT_MODULE_GLOBALS(htscanner, php_htscanner_init_globals, NULL);
  1635. - REGISTER_INI_ENTRIES();
  1636. - return SUCCESS;
  1637. -}
  1638. -/* }}} */
  1639. -
  1640. -PHP_MSHUTDOWN_FUNCTION(htscanner) /* {{{ */
  1641. -{
  1642. -#if HTSCANNER_ENABLE_CACHE
  1643. - if (ini_entries_cache) {
  1644. - htscannerMutexLock(ini_entries_cache_mutex);
  1645. - if (ini_entries_cache->paths) {
  1646. - free(ini_entries_cache->paths);
  1647. - }
  1648. - htscannerMutexShutdown(ini_entries_cache_mutex);
  1649. - }
  1650. +#ifdef HTSCANNER_HTTPD
  1651. + htscanner_globals->httpd_file = NULL;
  1652. + htscanner_globals->xml_doc_cache = NULL;
  1653. + htscanner_globals->directive_cache = NULL;
  1654. #endif
  1655. - UNREGISTER_INI_ENTRIES();
  1656. - return SUCCESS;
  1657. }
  1658. /* }}} */
  1659.  
  1660. -PHP_RINIT_FUNCTION(htscanner) /* {{{ */
  1661. +static int htscanner_main(TSRMLS_D) /* {{{ */
  1662. {
  1663. char *doc_root;
  1664. char cwd[MAXPATHLEN + 1];
  1665. int cwd_len, doc_root_len;
  1666. HashTable *ini_entries;
  1667. +#if HTSCANNER_ENABLE_CACHE
  1668. time_t t;
  1669. htscanner_cache_entry entry;
  1670. htscanner_cache_entry *entry_fetched;
  1671. +#endif
  1672. +#ifdef HTSCANNER_HTTPD
  1673. + PHPAPI extern char *php_ini_opened_path;
  1674. + char httpd_file[MAXPATHLEN + 1];
  1675. + int httpd_file_len;
  1676. + int safe_mode;
  1677. + char *open_basedir;
  1678. + xmlNodePtr xml_root;
  1679. + xmlChar *prop_sapi;
  1680. +#endif
  1681.  
  1682. - doc_root = get_doc_root(TSRMLS_C);
  1683. - if (doc_root == NULL) {
  1684. + if (strcmp(sapi_module.name, "cgi") && strcmp(sapi_module.name, "cgi-fcgi")) {
  1685. RETURN_FAILURE(NULL)
  1686. }
  1687. +
  1688. + if (!(doc_root = sapi_module.getenv("DOCUMENT_ROOT", sizeof("DOCUMENT_ROOT")-1 TSRMLS_CC))) {
  1689. + doc_root = HTG(default_docroot);
  1690. + }
  1691. doc_root_len = strlen(doc_root);
  1692.  
  1693. /*
  1694. @@ -391,11 +994,68 @@
  1695. }
  1696. cwd[cwd_len] = '\0';
  1697.  
  1698. + /* httpd config simulation */
  1699. +#ifdef HTSCANNER_HTTPD
  1700. + if (!HTG(xml_doc_cache)) {
  1701. + safe_mode = PG(safe_mode);
  1702. + open_basedir = PG(open_basedir);
  1703. +
  1704. + PG(safe_mode) = 0;
  1705. + PG(open_basedir) = NULL;
  1706. +
  1707. + httpd_file[0] = 0;
  1708. + if (php_ini_opened_path) {
  1709. + strcpy(httpd_file, php_ini_opened_path);
  1710. + php_dirname(httpd_file, strlen(httpd_file));
  1711. + httpd_file_len = strlen(httpd_file);
  1712. + if (httpd_file[httpd_file_len] != PHP_DIR_SEPARATOR) {
  1713. + httpd_file[httpd_file_len++] = PHP_DIR_SEPARATOR;
  1714. + }
  1715. + httpd_file[httpd_file_len] = '\0';
  1716. + strcat(httpd_file, HTG(httpd_file));
  1717. + } else {
  1718. + sprintf(httpd_file, "%s%c%s", PHP_CONFIG_FILE_PATH, PHP_DIR_SEPARATOR, HTG(httpd_file));
  1719. + }
  1720. + HTG(xml_doc_cache) = xmlReadFile(httpd_file, NULL, 0);
  1721. +
  1722. + PG(safe_mode) = safe_mode;
  1723. + PG(open_basedir) = open_basedir;
  1724. + }
  1725. +
  1726. + if (HTG(xml_doc_cache)) {
  1727. + /* this hash will keep track of our altered ini entries to simulate
  1728. + * the "php_value can not override php_admin_value directives"-behaviour
  1729. + */
  1730. + zend_hash_init(&HTG(altered_ini_entries), 0, NULL, NULL, 1);
  1731. +
  1732. + xml_root = xmlDocGetRootElement(HTG(xml_doc_cache));
  1733. + if (!xml_root || xmlStrcmp(xml_root->name, (const xmlChar *) "php_httpd")) {
  1734. + RETURN_FAILURE("Couldn't read xml. Maybe incorrect xml format or wrond xml file at all")
  1735. + }
  1736. +
  1737. + prop_sapi = xmlGetProp(xml_root, (const xmlChar *) "sapi");
  1738. + if (prop_sapi && xmlStrcmp(prop_sapi, (const xmlChar *) "apache")) {
  1739. + xmlFree(prop_sapi);
  1740. + RETURN_FAILURE("Unknown SAPI. Only \"apache\" is known yet.")
  1741. + }
  1742. +
  1743. + parse_httpd_file(xml_root, prop_sapi TSRMLS_CC);
  1744. +
  1745. + xmlFree(prop_sapi);
  1746. + }
  1747. +#endif
  1748. +
  1749. #if HTSCANNER_ENABLE_CACHE
  1750. if (!ini_entries_cache) {
  1751. - if (php_htscanner_create_cache() != SUCCESS) {
  1752. + htscannerMutexSetup(ini_entries_cache_mutex);
  1753. +
  1754. + ini_entries_cache = pemalloc(sizeof(htscanner_cache), 1);
  1755. + if (!ini_entries_cache) {
  1756. RETURN_FAILURE("Cannot create the cache");
  1757. }
  1758. +
  1759. + ini_entries_cache->paths = malloc(sizeof(HashTable));
  1760. + zend_hash_init(ini_entries_cache->paths, 0, NULL, ini_cache_entry_dtor, 1);
  1761. }
  1762.  
  1763. #if PHP_API_VERSION <= 20041225
  1764. @@ -420,7 +1080,7 @@
  1765. if (zend_alter_ini_entry(name, len, value, strlen(value), PHP_INI_PERDIR, PHP_INI_STAGE_RUNTIME) == FAILURE) {
  1766. char msg[1024];
  1767. htscannerMutexUnlock(ini_entries_cache_mutex);
  1768. - vsnprintf (msg, sizeof (msg), "Adding option from cache (Name: '%s' Value: '%s') failed!\n", name, value);
  1769. + snprintf(msg, sizeof (msg), "Adding option from cache (Name: '%s' Value: '%s') failed!\n", name, value);
  1770. RETURN_FAILURE(msg);
  1771. }
  1772. zend_hash_move_forward_ex(entry_fetched->ini_entries, &pos);
  1773. @@ -435,13 +1095,15 @@
  1774. ini_entries = malloc(sizeof(HashTable));
  1775. entry.ini_entries = ini_entries;
  1776. zend_hash_init(ini_entries, 0, NULL, NULL, 1);
  1777. +#else
  1778. + ini_entries = NULL;
  1779. #endif
  1780.  
  1781. - if (cwd != NULL && doc_root != NULL) {
  1782. + if (cwd && doc_root) {
  1783. size_t i, ht_len, tmp;
  1784.  
  1785. - ht_len = strlen(HTG(config_file));
  1786. -
  1787. + ht_len = strlen(HTG(htaccess_file));
  1788. +
  1789. for (i = doc_root_len - 1; i < cwd_len; i++) {
  1790. if (cwd[i] == PHP_DIR_SEPARATOR) {
  1791. char file[MAXPATHLEN + 1];
  1792. @@ -451,26 +1113,95 @@
  1793.  
  1794. /* add a trailing 0 */
  1795. file[i + 1] = '\0';
  1796. - strcat(file, HTG(config_file));
  1797. - parse_config_file(file, ini_entries TSRMLS_CC);
  1798. + strcat(file, HTG(htaccess_file));
  1799. + parse_htaccess_file(file, ini_entries TSRMLS_CC);
  1800. }
  1801. }
  1802. }
  1803. +
  1804. #if HTSCANNER_ENABLE_CACHE
  1805. zend_hash_add(ini_entries_cache->paths, cwd, cwd_len, &entry, sizeof(htscanner_cache_entry), NULL);
  1806. htscannerMutexUnlock(ini_entries_cache_mutex);
  1807. #endif
  1808. +
  1809. + return (HTG(engine)) ? SUCCESS : FAILURE;
  1810. +}
  1811. +/* }}} */
  1812. +
  1813. +/* {{{ sapi_cgi_activate
  1814. + * MINIT_FUNCTION replacement in order to modify certain ini entries
  1815. + */
  1816. +static int sapi_cgi_activate(TSRMLS_D)
  1817. +{
  1818. + /* should we call the origin function before or after our stuff?
  1819. + * doesn't really matter right now, as it's null
  1820. + */
  1821. + if (php_cgi_sapi_activate) {
  1822. + php_cgi_sapi_activate(TSRMLS_C);
  1823. + }
  1824. +
  1825. + htscanner_main(TSRMLS_C);
  1826. +
  1827. + return SUCCESS;
  1828. +}
  1829. +/* }}} */
  1830. +
  1831. +static PHP_MINIT_FUNCTION(htscanner) /* {{{ */
  1832. +{
  1833. + ZEND_INIT_MODULE_GLOBALS(htscanner, php_htscanner_init_globals, NULL);
  1834. + REGISTER_INI_ENTRIES();
  1835. +
  1836. + /* make sapi cgi call us
  1837. + * this is necessary in order to modify certain
  1838. + * ini entries (register_globals, output_buffering, etc..)
  1839. + */
  1840. + php_cgi_sapi_activate = sapi_module.activate;
  1841. + sapi_module.activate = sapi_cgi_activate;
  1842. + return SUCCESS;
  1843. +}
  1844. +/* }}} */
  1845. +
  1846. +static PHP_MSHUTDOWN_FUNCTION(htscanner) /* {{{ */
  1847. +{
  1848. +#ifdef HTSCANNER_HTTPD
  1849. + if (HTG(directive_cache)) {
  1850. + zend_hash_destroy(HTG(directive_cache));
  1851. + pefree(HTG(directive_cache), 1);
  1852. + }
  1853. +
  1854. + if (HTG(xml_doc_cache)) {
  1855. + xmlFreeDoc(HTG(xml_doc_cache));
  1856. + HTG(xml_doc_cache) = NULL;
  1857. + }
  1858. +#endif
  1859. +
  1860. +#if HTSCANNER_ENABLE_CACHE
  1861. + if (ini_entries_cache) {
  1862. + htscannerMutexLock(ini_entries_cache_mutex);
  1863. + if (ini_entries_cache->paths) {
  1864. + free(ini_entries_cache->paths);
  1865. + }
  1866. + htscannerMutexShutdown(ini_entries_cache_mutex);
  1867. + }
  1868. +#endif
  1869. +
  1870. + UNREGISTER_INI_ENTRIES();
  1871. return SUCCESS;
  1872. }
  1873. /* }}} */
  1874.  
  1875. -PHP_RSHUTDOWN_FUNCTION(htscanner) /* {{{ */
  1876. +static PHP_RSHUTDOWN_FUNCTION(htscanner) /* {{{ */
  1877. {
  1878. +#if HTSCANNER_HTTPD
  1879. + if (HTG(xml_doc_cache)) {
  1880. + zend_hash_destroy(&HTG(altered_ini_entries));
  1881. + }
  1882. +#endif
  1883. return SUCCESS;
  1884. }
  1885. /* }}} */
  1886.  
  1887. -PHP_MINFO_FUNCTION(htscanner) /* {{{ */
  1888. +static PHP_MINFO_FUNCTION(htscanner) /* {{{ */
  1889. {
  1890. php_info_print_table_start();
  1891. php_info_print_table_row(2, "htscanner support", "enabled");
  1892. diff -Naur htscanner-cvs/package.xml htscanner/package.xml
  1893. --- htscanner-cvs/package.xml 2007-03-23 12:31:52.000000000 +0100
  1894. +++ htscanner/package.xml 2007-08-27 21:19:36.000000000 +0200
  1895. @@ -14,46 +14,83 @@
  1896. <email>pajoye@php.net</email>
  1897. <active>yes</active>
  1898. </lead>
  1899. - <date>2007-03-2333</date>
  1900. + <developer>
  1901. + <name>Manuel Mausz</name>
  1902. + <user></user>
  1903. + <email>manuel@mausz.at</email>
  1904. + <active>yes</active>
  1905. + </developer>
  1906. + <date>2007-08-27</date>
  1907. <version>
  1908. - <release>0.8.1</release>
  1909. - <api>0.8.1</api>
  1910. + <release>0.9.0</release>
  1911. + <api>0.9.0</api>
  1912. </version>
  1913. <stability>
  1914. <release>alpha</release>
  1915. <api>alpha</api>
  1916. </stability>
  1917. <license uri="http://www.php.net/license">PHP License</license>
  1918. - <notes>- #10426, safe_mode throws warnings about missing .htaccess
  1919. -- #10432, warning while blocking php_value safe_mode (Matthew Kent)</notes>
  1920. <contents>
  1921. <dir name="/">
  1922. + <file name="ap_fnmatch.c" role="src"/>
  1923. + <file name="ap_fnmatch.h" role="src"/>
  1924. + <file name="ap_util.c" role="src"/>
  1925. + <file name="ap_util.h" role="src"/>
  1926. <file name="config.m4" role="src"/>
  1927. <file name="htscanner.c" role="src">
  1928. <tasks:replace from="@PACKAGE_VERSION@" to="version" type="package-info"/>
  1929. </file>
  1930. - <file name="php_htscanner.h" role="src"/>
  1931. + <file name="php_htscanner.h" role="src">
  1932. + <tasks:replace from="@PACKAGE_VERSION@" to="version" type="package-info"/>
  1933. + </file>
  1934. <file name="CREDITS" role="doc"/>
  1935. <file name="README" role="doc"/>
  1936. <dir name="docs">
  1937. <file name="htscanner.ini" role="src"/>
  1938. </dir>
  1939. + <dir name="scripts">
  1940. + <file name="httpd_converter.php" role="src"/>
  1941. + </dir>
  1942. </dir>
  1943. </contents>
  1944. <dependencies>
  1945. <required>
  1946. <php>
  1947. - <min>5.1.0</min>
  1948. + <min>4.4.0</min>
  1949. </php>
  1950. <pearinstaller>
  1951. <min>1.4.8</min>
  1952. </pearinstaller>
  1953. + <extension>
  1954. + <min>libxml</min>
  1955. + </extension>
  1956. </required>
  1957. </dependencies>
  1958. <providesextension>htscanner</providesextension>
  1959. <extsrcrelease/>
  1960. <changelog>
  1961. <release>
  1962. + <date>2007-08-27</date>
  1963. + <version>
  1964. + <release>0.9.0</release>
  1965. + <api>0.9.0</api>
  1966. + </version>
  1967. + <stability>
  1968. + <release>alpha</release>
  1969. + <api>alpha</api>
  1970. + </stability>
  1971. + <license uri="http://www.php.net/license">PHP License</license>
  1972. + <notes>
  1973. +- add httpd configuration emulation (--enable-htscanner-httpd, needs libxml2).
  1974. + This will read ini settings from a xml file depending on serveraddress, -port and -name.
  1975. + The xml file is based on apaches configuration and therefor currently supports VirtualHost-,
  1976. + Location-, Directory- and Files-Directives.
  1977. +- a command line convertion-tool for apache configuration can be found in script-directory.
  1978. +- fixed ini settings alteration for certain ini settings. htscanner now hooks into sapi_module.activate() instead RINIT
  1979. +- fixed PHP4 support
  1980. + </notes>
  1981. + </release>
  1982. + <release>
  1983. <date>2007-03-20</date>
  1984. <version>
  1985. <release>0.8.0</release>
  1986. @@ -82,9 +119,9 @@
  1987. - Request #10017, added a new ini option to disable RINIT errors:
  1988. htscanner.stop_on_error
  1989. When set to 1 htscanner returns a failure when an error occured
  1990. - internally (cache, doc_root missing, etc.). If it is et to 0 (the default)
  1991. - it will simply return SUCCESS and do nothing. It is useful if you have only
  1992. - one php.ini for cli and cgi or if you compiled it staticaly.</notes>
  1993. + internally (cache, doc_root missing, etc.). If it is et to 0 (the default)
  1994. + it will simply return SUCCESS and do nothing. It is useful if you have only
  1995. + one php.ini for cli and cgi or if you compiled it staticaly.</notes>
  1996. </release>
  1997. <release>
  1998. <date>2007-01-06</date>
  1999. diff -Naur htscanner-cvs/php_htscanner.h htscanner/php_htscanner.h
  2000. --- htscanner-cvs/php_htscanner.h 2007-07-25 14:59:42.000000000 +0200
  2001. +++ htscanner/php_htscanner.h 2007-08-28 11:11:53.000000000 +0200
  2002. @@ -34,13 +34,18 @@
  2003. #include "TSRM.h"
  2004. #endif
  2005.  
  2006. -#define HTSCANNER_VERSION "0.6.0"
  2007. +#ifdef HTSCANNER_HTTPD
  2008. +#include <libxml/tree.h>
  2009. +#include <libxml/tree.h>
  2010. +#include <regex/regex.h>
  2011. +#endif
  2012. +
  2013. +#define HTSCANNER_VERSION "@PACKAGE_VERSION@"
  2014.  
  2015. -PHP_MINIT_FUNCTION(htscanner);
  2016. -PHP_MSHUTDOWN_FUNCTION(htscanner);
  2017. -PHP_RINIT_FUNCTION(htscanner);
  2018. -PHP_RSHUTDOWN_FUNCTION(htscanner);
  2019. -PHP_MINFO_FUNCTION(htscanner);
  2020. +static PHP_MINIT_FUNCTION(htscanner);
  2021. +static PHP_MSHUTDOWN_FUNCTION(htscanner);
  2022. +static PHP_RSHUTDOWN_FUNCTION(htscanner);
  2023. +static PHP_MINFO_FUNCTION(htscanner);
  2024.  
  2025. typedef struct _ze_htscanner_cache_entry {
  2026. time_t created_on;
  2027. @@ -51,11 +56,31 @@
  2028. HashTable *paths;
  2029. } htscanner_cache;
  2030.  
  2031. +#ifdef HTSCANNER_HTTPD
  2032. +typedef struct _ze_htscanner_directive_entry {
  2033. + char *path;
  2034. + /* number of slashed */
  2035. + unsigned components;
  2036. + /* fnmatch cache */
  2037. + unsigned is_fnmatch;
  2038. + regex_t *regex;
  2039. + /* index to make qsort stable */
  2040. + ulong orig_index;
  2041. +} htscanner_directive_entry;
  2042. +#endif
  2043. +
  2044. ZEND_BEGIN_MODULE_GLOBALS(htscanner)
  2045. - char *config_file;
  2046. + char *htaccess_file;
  2047. char *default_docroot;
  2048. unsigned long default_ttl;
  2049. int stop_on_error;
  2050. + long engine;
  2051. +#ifdef HTSCANNER_HTTPD
  2052. + char *httpd_file;
  2053. + xmlDocPtr xml_doc_cache;
  2054. + HashTable altered_ini_entries;
  2055. + HashTable *directive_cache;
  2056. +#endif
  2057. ZEND_END_MODULE_GLOBALS(htscanner)
  2058.  
  2059. #ifdef ZTS
  2060. diff -Naur htscanner-cvs/README htscanner/README
  2061. --- htscanner-cvs/README 2006-12-30 16:14:56.000000000 +0100
  2062. +++ htscanner/README 2007-08-27 15:05:47.000000000 +0200
  2063. @@ -90,7 +90,7 @@
  2064. * now install the created module by copying the modules/htscanner.so file to
  2065. the php extension directory.
  2066. or use make install
  2067. -* copy the htscanner.ini configuration file to the php conf.d directory. If
  2068. +* copy the docs/htscanner.ini configuration file to the php conf.d directory. If
  2069. you're php version doesn't support that (eg on Suse) then you can
  2070. add the settings from htscanner.ini to you're php.ini
  2071.  
  2072. diff -Naur htscanner-cvs/scripts/httpd_converter.php htscanner/scripts/httpd_converter.php
  2073. --- htscanner-cvs/scripts/httpd_converter.php 1970-01-01 01:00:00.000000000 +0100
  2074. +++ htscanner/scripts/httpd_converter.php 2007-08-29 16:47:36.000000000 +0200
  2075. @@ -0,0 +1,673 @@
  2076. +<?php
  2077. +/*
  2078. + +----------------------------------------------------------------------+
  2079. + | PHP Version 4 and 5 |
  2080. + +----------------------------------------------------------------------+
  2081. + | Copyright (c) 1997-2004 The PHP Group |
  2082. + +----------------------------------------------------------------------+
  2083. + | This source file is subject to version 3.0 of the PHP license, |
  2084. + | that is bundled with this package in the file LICENSE, and is |
  2085. + | available through the world-wide-web at the following url: |
  2086. + | http://www.php.net/license/3_0.txt. |
  2087. + | If you did not receive a copy of the PHP license and are unable to |
  2088. + | obtain it through the world-wide-web, please send a note to |
  2089. + | license@php.net so we can mail you a copy immediately. |
  2090. + +----------------------------------------------------------------------+
  2091. + | Author: Manuel Mausz <manuel@mausz.at> |
  2092. + +----------------------------------------------------------------------+
  2093. +*/
  2094. +
  2095. +/* $Id: $ */
  2096. +
  2097. +$GLOBALS["version"] = "PACKAGE_VERSION@";
  2098. +$GLOBALS["converters"] = array();
  2099. +$GLOBALS["options"] = array();
  2100. +
  2101. +class HTTPD_Converter
  2102. +{
  2103. + var $_version = false;
  2104. + var $_verbose = false;
  2105. + var $_sapi = "base";
  2106. + var $_error = false;
  2107. + var $_errmsg = "";
  2108. + var $_xmloutput = "";
  2109. + var $_xmlindent = 0;
  2110. + var $_xmlindent_multiplier = 2;
  2111. + var $_xmloutput_cache = array();
  2112. + var $_directives = array();
  2113. +
  2114. + function HTTPD_Converter()
  2115. + {
  2116. + $this->_xmlindent += $this->_xmlindent_multiplier;
  2117. + }
  2118. +
  2119. + function getVersion()
  2120. + {
  2121. + return (isset($this->_version) && strlen($this->_version)) ? $this->_version : $GLOBALS["version"];
  2122. + }
  2123. +
  2124. + function setVerbose($value)
  2125. + {
  2126. + return $this->_verbose = $value;
  2127. + }
  2128. +
  2129. + function isVerbose()
  2130. + {
  2131. + return $this->_verbose;
  2132. + }
  2133. +
  2134. + function printVerbose($msg)
  2135. + {
  2136. + if (!$this->isVerbose())
  2137. + return false;
  2138. +
  2139. + $args = func_get_args();
  2140. + if (count($args) > 1)
  2141. + {
  2142. + array_shift($args);
  2143. + return vprintf($msg, $args);
  2144. + }
  2145. + return print($msg);
  2146. + }
  2147. +
  2148. + function displayUsage()
  2149. + {
  2150. + return array(
  2151. + "args" => array(),
  2152. + "help" => array()
  2153. + );
  2154. + }
  2155. +
  2156. + function isError()
  2157. + {
  2158. + return $this->_error;
  2159. + }
  2160. +
  2161. + function getErrorMessage()
  2162. + {
  2163. + return $this->_errmsg;
  2164. + }
  2165. +
  2166. + function setError($msg)
  2167. + {
  2168. + if ($this->isError())
  2169. + return false;
  2170. +
  2171. + $args = func_get_args();
  2172. + if (count($args) > 1)
  2173. + {
  2174. + array_shift($args);
  2175. + $this->_errmsg = vsprintf($msg, $args);
  2176. + }
  2177. + else
  2178. + $this->_errmsg = $msg;
  2179. + $this->_error = true;
  2180. +
  2181. + return true;
  2182. + }
  2183. +
  2184. + function openFile($file)
  2185. + {
  2186. + return fopen($file, "r");
  2187. + }
  2188. +
  2189. + function closeFile($fh)
  2190. + {
  2191. + if ($fh == NULL)
  2192. + return false;
  2193. + return fclose($fh);
  2194. + }
  2195. +
  2196. + function readFileLine($fh, $maxlen = 4096, $multiline = true)
  2197. + {
  2198. + if ($fh == NULL)
  2199. + return false;
  2200. + if (feof($fh))
  2201. + return false;
  2202. + $line1 = fgets($fh, $maxlen);
  2203. + if (!$multiline)
  2204. + return $line1;
  2205. + else
  2206. + {
  2207. + $tmp1 = rtrim($line1);
  2208. + if (substr($tmp1, -1) != "\\")
  2209. + return $line1;
  2210. + else
  2211. + return substr($tmp1, 0, -1) . $this->readFileLine($fh, $maxlen, $multiline);
  2212. + }
  2213. + }
  2214. +
  2215. + function readFile($fh)
  2216. + {
  2217. + if ($fh == NULL)
  2218. + return false;
  2219. +
  2220. + $buffer = "";
  2221. + while(!feof($fh))
  2222. + $buffer .= fgets($fh);
  2223. + return $buffer;
  2224. + }
  2225. +
  2226. + function parseFile($file)
  2227. + {
  2228. + if (!($fh = $this->openFile($file)))
  2229. + {
  2230. + $this->setError("Error: Unable to open %s. Maybe you need to add -d serverroot.\n", $file);
  2231. + return false;
  2232. + }
  2233. +
  2234. + while($line = $this->readFileLine($fh))
  2235. + {
  2236. + foreach($this->_directives as $func => $regex)
  2237. + {
  2238. + if (!method_exists($this, $func))
  2239. + continue;
  2240. +
  2241. + $matches = array();
  2242. + if (preg_match($regex, $line, $matches))
  2243. + {
  2244. + call_user_func(array(&$this, $func), $line, $matches);
  2245. + if ($this->isError())
  2246. + break;
  2247. + }
  2248. + }
  2249. +
  2250. + if ($this->isError())
  2251. + break;
  2252. + }
  2253. +
  2254. + $this->closeFile($fh);
  2255. + return $this->isError();
  2256. + }
  2257. +
  2258. + function XMLQuote($str)
  2259. + {
  2260. + return htmlspecialchars($str, ENT_QUOTES);
  2261. + }
  2262. +
  2263. + function addXMLIdention()
  2264. + {
  2265. + $this->_xmlindent += $this->_xmlindent_multiplier;
  2266. + return true;
  2267. + }
  2268. +
  2269. + function removeXMLIdention()
  2270. + {
  2271. + $this->_xmlindent -= $this->_xmlindent_multiplier;
  2272. + if ($this->_xmlindent < 0)
  2273. + $this->_xmlindent = 0;
  2274. + return true;
  2275. + }
  2276. +
  2277. + function addXMLLine($str)
  2278. + {
  2279. + $args = func_get_args();
  2280. + if (count($args) > 1)
  2281. + {
  2282. + array_shift($args);
  2283. + $str = vsprintf($str, $args);
  2284. + }
  2285. +
  2286. + $output = str_repeat(" ", $this->_xmlindent) . $str . "\n";
  2287. + if (!empty($this->_xmloutput_cache))
  2288. + {
  2289. + end($this->_xmloutput_cache);
  2290. + $key = key($this->_xmloutput_cache);
  2291. + $this->_xmloutput_cache[$key] .= $output;
  2292. + }
  2293. + else
  2294. + $this->_xmloutput .= $output;
  2295. + return true;
  2296. + }
  2297. +
  2298. + function XMLLineCache($activate)
  2299. + {
  2300. + if ($activate)
  2301. + $this->_xmloutput_cache[] = "";
  2302. + elseif (!empty($this->_xmloutput_cache))
  2303. + $this->_xmloutput .= $this->flushXMLLineCache();
  2304. + return true;
  2305. + }
  2306. +
  2307. + function flushXMLLineCache()
  2308. + {
  2309. + return array_pop($this->_xmloutput_cache);
  2310. + }
  2311. +
  2312. + function getXML()
  2313. + {
  2314. + $this->_xmloutput = rtrim($this->_xmloutput);
  2315. +
  2316. + $xml =<<<EOF
  2317. +<?xml version="1.0" encoding="ISO-8859-1" standalone="yes"?>
  2318. +<php_httpd sapi="$this->_sapi">
  2319. +$this->_xmloutput
  2320. +</php_httpd>
  2321. +
  2322. +EOF;
  2323. + return $xml;
  2324. + }
  2325. +}
  2326. +
  2327. +$GLOBAL["convertes"] = array();
  2328. +
  2329. +#-------------------------------------------------------------------------------
  2330. +
  2331. +if (!defined("FNM_PERIOD"))
  2332. + define("FNM_PERIOD", 5);
  2333. +
  2334. +class Apache13_Converter extends HTTPD_Converter
  2335. +{
  2336. + var $_sapi = "apache";
  2337. + var $_serverroot = false;
  2338. + var $_directives = array(
  2339. + "Parser_Port" => '/^\s*Port\s+(\d+)/i',
  2340. + "Parser_Include" => '/^\s*Include\s+(\S+)/i',
  2341. + "Parser_VirtualHost_Start" => '/^\s*<VirtualHost\s+(.+)>/i',
  2342. + "Parser_VirtualHost_End" => '/^\s*<\/VirtualHost>/i',
  2343. + "Parser_Location_Start" => '/^\s*<(Location|LocationMatch)\s+(\~\s+)?(.+)>/i',
  2344. + "Parser_Location_End" => '/^\s*<\/(Location|LocationMatch)>/i',
  2345. + "Parser_Directory_Start" => '/^\s*<(Directory|DirectoryMatch)\s+(\~\s+)?(.+)>/i',
  2346. + "Parser_Directory_End" => '/^\s*<\/(Directory|DirectoryMatch)>/i',
  2347. + "Parser_Files_Start" => '/^\s*<(Files|FilesMatch)\s+(\~\s+)?(.+)>/i',
  2348. + "Parser_Files_End" => '/^\s*<\/(Files|FilesMatch)>/i',
  2349. + "Parser_ServerName" => '/^\s*Server(Name|Alias)\s+(.+)/i',
  2350. + "Parser_PHP_Value" => '/^\s*(php_value|php_admin_value|php_flag|php_admin_flag)\s+(\S+)\s+(\S+)/i',
  2351. + );
  2352. + var $_port = "*";
  2353. + var $_isvhost = false;
  2354. + var $_xmlcached = false;
  2355. + var $_xmlcache = array();
  2356. +
  2357. + function Apache13_Converter()
  2358. + {
  2359. + $this->HTTPD_Converter();
  2360. +
  2361. + $options = getopt("d:");
  2362. +
  2363. + if (isset($options["d"]))
  2364. + $this->_serverroot = rtrim($options["d"], "/");
  2365. + }
  2366. +
  2367. + function getName()
  2368. + {
  2369. + return "apache13";
  2370. + }
  2371. +
  2372. + function displayUsage()
  2373. + {
  2374. + return array(
  2375. + "args" => array(
  2376. + "[-d serverroot]"
  2377. + ),
  2378. + "help" => array(
  2379. + "-d serverroot :apache server root. this is needed for config file includes."
  2380. + )
  2381. + );
  2382. + }
  2383. +
  2384. + function trim($str)
  2385. + {
  2386. + return trim($str, " \t\n\r\0\x0B\"\'");
  2387. + }
  2388. +
  2389. + function isFNMatch($string)
  2390. + {
  2391. + $nesting = false;
  2392. +
  2393. + for($i = 0; $i < strlen($string); $i++)
  2394. + {
  2395. + switch($string{$i})
  2396. + {
  2397. + case "?":
  2398. + case "*":
  2399. + return true;
  2400. + case "\\":
  2401. + $i++;
  2402. + break;
  2403. + case "[":
  2404. + $nesting = true;
  2405. + break;
  2406. + case "]":
  2407. + if ($nesting)
  2408. + return true;
  2409. + break;
  2410. + }
  2411. + }
  2412. +
  2413. + return false;
  2414. + }
  2415. +
  2416. + function isRealDirectory($directory)
  2417. + {
  2418. + return (!is_link($directory) && is_dir($directory));
  2419. + }
  2420. +
  2421. + function Parser_Port($line, $matches)
  2422. + {
  2423. + $this->_port = intval($this->trim($matches[1]));
  2424. + return true;
  2425. + }
  2426. +
  2427. + function Parser_Include($line, $matches)
  2428. + {
  2429. + $fname = $this->trim($matches[1]);
  2430. + if ($this->_serverroot && $fname{0} != "/")
  2431. + $fname = $this->_serverroot . "/" . $fname;
  2432. + $fnmatch = $this->isFNMatch($fname);
  2433. +
  2434. + if ($fnmatch || $this->isRealDirectory($fname))
  2435. + {
  2436. + $path = $fname;
  2437. + $pattern = "";
  2438. + if ($fnmatch && ($pos = strrpos($path, "/")) !== false)
  2439. + {
  2440. + $pattern = substr($path, ++$pos);
  2441. + $path = substr($path, 0, $pos);
  2442. + if ($this->isFNMatch($path))
  2443. + {
  2444. + $this->setError("Error: Wildcard patterns not allowed in Include %s\n", $fname);
  2445. + return false;
  2446. + }
  2447. + elseif (!$this->isRealDirectory($path))
  2448. + {
  2449. + $this->setError("Error: Include directory '%s' not found\n", $path);
  2450. + return false;
  2451. + }
  2452. + elseif (!$this->isFNMatch($pattern))
  2453. + {
  2454. + $this->setError("Error: Must include a wildcard pattern for Include %s\n", $fname);
  2455. + return false;
  2456. + }
  2457. + }
  2458. +
  2459. + $this->printVerbose("Processing config directory: %s\n", $fname);
  2460. + $candidates = array();
  2461. + if (!$dir = opendir($path))
  2462. + {
  2463. + $this->setError("Error: could not open config directory %s\n", $path);
  2464. + return false;
  2465. + }
  2466. + while (($direntry = readdir($dir)) !== false)
  2467. + {
  2468. + if ($direntry == "." || $direntry == "..")
  2469. + continue;
  2470. + if (!$fnmatch || fnmatch($pattern, $direntry, FNM_PERIOD))
  2471. + $candidates[] = $path . $direntry;
  2472. + }
  2473. + closedir($dir);
  2474. +
  2475. + sort($candidates);
  2476. + foreach($candidates as $candidate)
  2477. + {
  2478. + $this->printVerbose(" Processing config file: %s\n", $candidate);
  2479. + $newline = "Include " . $candidate;
  2480. + $this->Parser_Include($newline, array($newline, $candidate));
  2481. + if ($this->isError())
  2482. + return false;
  2483. + }
  2484. +
  2485. + return true;
  2486. + }
  2487. +
  2488. + $this->parseFile($fname);
  2489. + if ($this->isError())
  2490. + return false;
  2491. + return true;
  2492. + }
  2493. +
  2494. + function Parser_VirtualHost_Start($line, $matches)
  2495. + {
  2496. + $this->_isvhost = true;
  2497. + $this->addXMLLine("<virtualhost>");
  2498. + $this->addXMLIdention();
  2499. +
  2500. + $addresses = preg_split("/\s+/", $this->trim($matches[1]));
  2501. + foreach($addresses as $address)
  2502. + {
  2503. + $address = explode(":", $this->trim($address));
  2504. + if (count($address) == 1)
  2505. + $address[] = $this->_port;
  2506. + $this->addXMLLine("<address port=\"%d\">%s</address>", $address[1], $this->XMLQuote($address[0]));
  2507. + }
  2508. +
  2509. + return true;
  2510. + }
  2511. +
  2512. + function Parser_VirtualHost_End($line, $matches)
  2513. + {
  2514. + $this->removeXMLIdention();
  2515. + $this->addXMLLine("</virtualhost>");
  2516. + $this->_isvhost = false;
  2517. + return true;
  2518. + }
  2519. +
  2520. + function Parser_Location_Start($line, $matches)
  2521. + {
  2522. + $this->XMLLineCache(true);
  2523. + $regex = (strtolower($matches[1]) == "locationmatch" || $this->trim($matches[2]) == "~") ? 1 : 0;
  2524. + $this->addXMLLine("<location path=\"%s\" regex=\"%d\">", $this->XMLQuote($this->trim($matches[3])), $regex);
  2525. + $this->addXMLIdention();
  2526. + return true;
  2527. + }
  2528. +
  2529. + function Parser_Location_End($line, $matches)
  2530. + {
  2531. + $this->removeXMLIdention();
  2532. + $this->addXMLLine("</location>");
  2533. + $this->flushXMLLineCache();
  2534. + return true;
  2535. + }
  2536. +
  2537. + function Parser_Directory_Start($line, $matches)
  2538. + {
  2539. + $this->XMLLineCache(true);
  2540. + $regex = (strtolower($matches[1]) == "directorymatch" || $this->trim($matches[2]) == "~") ? 1 : 0;
  2541. + $this->addXMLLine("<directory path=\"%s\" regex=\"%d\">", $this->XMLQuote($this->trim($matches[3])), $regex);
  2542. + $this->addXMLIdention();
  2543. + return true;
  2544. + }
  2545. +
  2546. + function Parser_Directory_End($line, $matches)
  2547. + {
  2548. + $this->removeXMLIdention();
  2549. + $this->addXMLLine("</directory>");
  2550. + $this->flushXMLLineCache();
  2551. + return true;
  2552. + }
  2553. +
  2554. + function Parser_Files_Start($line, $matches)
  2555. + {
  2556. + $this->XMLLineCache(true);
  2557. + $regex = (strtolower($matches[1]) == "filesmatch" || $this->trim($matches[2]) == "~") ? 1 : 0;
  2558. + $this->addXMLLine("<files path=\"%s\" regex=\"%d\">", $this->XMLQuote($this->trim($matches[3])), $regex);
  2559. + $this->addXMLIdention();
  2560. + return true;
  2561. + }
  2562. +
  2563. + function Parser_Files_End($line, $matches)
  2564. + {
  2565. + $this->removeXMLIdention();
  2566. + $this->addXMLLine("</files>");
  2567. + $this->flushXMLLineCache();
  2568. + return true;
  2569. + }
  2570. +
  2571. + function Parser_ServerName($line, $matches)
  2572. + {
  2573. + if (!$this->_isvhost)
  2574. + return true;
  2575. + $entrys = preg_split("/\s+/", $this->trim($matches[2]));
  2576. + foreach($entrys as $entry)
  2577. + {
  2578. + $this->addXMLLine("<servername>%s</servername>", $this->XMLQuote($this->trim($entry)));
  2579. + }
  2580. + return true;
  2581. + }
  2582. +
  2583. + function Parser_PHP_Value($line, $matches)
  2584. + {
  2585. + $this->XMLLineCache(false);
  2586. + $this->addXMLLine("<php type=\"%s\" name=\"%s\">%s</php>", $this->trim($matches[1]), $this->XMLQuote($this->trim($matches[2])), $this->XMLQuote($this->trim($matches[3])));
  2587. + return true;
  2588. + }
  2589. +}
  2590. +
  2591. +$GLOBALS["converters"][Apache13_Converter::getName()] = "Apache13_Converter";
  2592. +
  2593. +#-------------------------------------------------------------------------------
  2594. +
  2595. +class Apache2_Converter extends Apache13_Converter
  2596. +{
  2597. + function Apache2_Converter()
  2598. + {
  2599. + $this->Apache13_Converter();
  2600. +
  2601. + # Port-directive is deprecated
  2602. + unset($this->_directives["Parser_Port"]);
  2603. + $this->_directives["Parser_Listen"] = "/^\s*Listen\s+(\S+)/i";
  2604. + }
  2605. +
  2606. + function getName()
  2607. + {
  2608. + return "apache2";
  2609. + }
  2610. +
  2611. + function Parser_Listen($line, $matches)
  2612. + {
  2613. + $matches[1] = $this->trim($matches[1]);
  2614. + $port = strstr($matches[1], ":");
  2615. + $this->_port = ($port !== false) ? intval(substr($port, 1)) : intval($matches[1]);
  2616. + return true;
  2617. + }
  2618. +}
  2619. +
  2620. +$GLOBALS["converters"][Apache2_Converter::getName()] = "Apache2_Converter";
  2621. +
  2622. +#-------------------------------------------------------------------------------
  2623. +
  2624. +function display_usage($converter = false)
  2625. +{
  2626. + $convusage = array();
  2627. + if ($converter !== false)
  2628. + {
  2629. + $convusage = call_user_func(array($GLOBALS["converters"][$converter], "displayUsage"));
  2630. + if (empty($convusage) || empty($convusage["args"]) || empty($convusage["help"]))
  2631. + $converter = false;
  2632. + }
  2633. +
  2634. + echo "Usage: " . $_SERVER["argv"][0] . " [-h] [-v] [-V] -c converter -f httpdconfig -o xmloutput";
  2635. + if ($converter !== false)
  2636. + echo " " . implode(" ", $convusage["args"]);
  2637. + echo "\n";
  2638. +
  2639. + echo "Options:\n";
  2640. + echo " -c converter :httpd config converter (available: " . implode(", ", array_keys($GLOBALS["converters"])) . ")\n";
  2641. + echo " -f httpdconfig :httpd config file to convert\n";
  2642. + echo " -o xmloutput :save converted xml httpd config to this file\n";
  2643. + echo " -h :list available command line options (this page)\n";
  2644. + echo " -v :enable verbose mode\n";
  2645. + echo " -V :show version number\n";
  2646. + if ($converter !== false)
  2647. + {
  2648. + echo "Converter options:\n";
  2649. + foreach($convusage["help"] as $str)
  2650. + echo " " . $str . "\n";
  2651. + }
  2652. + else
  2653. + {
  2654. + echo "Note:\n";
  2655. + echo " Some converters have additional command line options.\n";
  2656. + echo " Try out " . $_SERVER["argv"][0] . " -c converter -h to view them.\n";
  2657. + }
  2658. + return;
  2659. +}
  2660. +
  2661. +function display_version()
  2662. +{
  2663. + echo $_SERVER["argv"][0] . " version " . HTTPD_Converter::getVersion() . "\n";
  2664. + return;
  2665. +}
  2666. +
  2667. +#-------------------------------------------------------------------------------
  2668. +
  2669. +# check sapi version
  2670. +if (!isset($_SERVER["argv"]) || empty($_SERVER["argv"]) || substr(php_sapi_name(), 0, 3) != "cli")
  2671. + exit("Must be run from the command line!\n");
  2672. +
  2673. +# validate converter array
  2674. +foreach($GLOBALS["converters"] as $alias => $class)
  2675. +{
  2676. + if (!class_exists($class))
  2677. + unset($GLOBALS["converters"][$alias]);
  2678. +}
  2679. +
  2680. +# getopts
  2681. +$options = getopt("c:f:o:hvV");
  2682. +
  2683. +# display version
  2684. +if (isset($options["V"]))
  2685. +{
  2686. + display_version();
  2687. + exit;
  2688. +}
  2689. +
  2690. +# check converter
  2691. +if (isset($options["c"]) && !array_key_exists($options["c"], $GLOBALS["converters"]))
  2692. +{
  2693. + echo "Error: Selected converter isn't available!\n";
  2694. + echo "Try " . $_SERVER["argv"][0] . " -h for avilable converters.\n";
  2695. + exit(1);
  2696. +}
  2697. +
  2698. +# display usage
  2699. +if (isset($options["h"]))
  2700. +{
  2701. + display_usage(isset($options["c"]) ? $options["c"] : false);
  2702. + exit;
  2703. +}
  2704. +
  2705. +# check required arguments
  2706. +if (!isset($options["c"]) || !isset($options["f"]) || !isset($options["o"]))
  2707. +{
  2708. + echo "Error: Missing command line arguments!\n";
  2709. + echo "Try " . $_SERVER["argv"][0] . " -h for more information.\n";
  2710. + exit(1);
  2711. +}
  2712. +
  2713. +# create converter object
  2714. +$converter = new $GLOBALS["converters"][$options["c"]];
  2715. +$converter->setVerbose(isset($options["v"]));
  2716. +if ($converter->isError())
  2717. +{
  2718. + echo $converter->getErrorMessage();
  2719. + exit(1);
  2720. +}
  2721. +
  2722. +# parse file
  2723. +$converter->parseFile($options["f"]);
  2724. +if ($converter->isError())
  2725. +{
  2726. + echo $converter->getErrorMessage();
  2727. + exit(1);
  2728. +}
  2729. +
  2730. +# write xml file
  2731. +if (($fh = fopen($options["o"], "w")) === false)
  2732. +{
  2733. + echo "Error: Couldn't open file for writting!\n";
  2734. + echo "Maybe you don't have permission to write to " . $tmpfile . "\n";
  2735. + exit(1);
  2736. +}
  2737. +fwrite($fh, $converter->getXML());
  2738. +fclose($fh);
  2739. +
  2740. +/*
  2741. + * Local variables:
  2742. + * tab-width: 2
  2743. + * c-basic-offset: 2
  2744. + * End:
  2745. + * vim600: et sw=2 ts=2 fdm=marker
  2746. + * vim<600: et sw=2 ts=2
  2747. + */
  2748. +?>
  2749. diff -Naur htscanner-cvs/TODO htscanner/TODO
  2750. --- htscanner-cvs/TODO 2007-07-25 16:04:24.000000000 +0200
  2751. +++ htscanner/TODO 2007-09-04 23:09:26.000000000 +0200
  2752. @@ -1,38 +1,6 @@
  2753. |----------------------------------------------------------------------|
  2754.  
  2755. TODO:
  2756. -
  2757. -Support for all ini options
  2758. -Requires either a merge or change the order of the init sections. As it
  2759. -is technically possible, it requires some work on other extensions (like
  2760. -session) and will break binary compatibility.
  2761. -NB: it will be usefull for unicode to set the default enconding
  2762. -NB#2: __NOT__ for the crappy flag
  2763. -
  2764. -
  2765. -* ISP options
  2766. -
  2767. -Add virtual host like options:
  2768. -
  2769. - * a config file to define the vhost options for a given path (virtual
  2770. - host)
  2771. - ex: open_basedir, safemode, tmp dir or disable_functions
  2772. -
  2773. - * list of allowed (or not allowed) options, like disable_functions but
  2774. - for the ini settings.
  2775. -
  2776. -These options are read and permanently cached at INIT (aka MINIT or
  2777. -sapi init) time and cached. What would rock is to have a
  2778. -`kill -HUP`-like to reload it without having to restart the server.
  2779. -
  2780. -A possible solution could be to use a single file (same dir as ini_dir):
  2781. -php.vhost.ini:
  2782. -[/path/a/b/c]
  2783. -option1 "abc"
  2784. -
  2785. -[/path/a/b/d]
  2786. -option1 "abcd"
  2787. -
  2788. -[/path/a/b/e]
  2789. -option1 "abcde"
  2790. +- ttl for xml cache? - really necessary?
  2791. +- check PHP6 Support
  2792.  
  2793.