Difference Between Revision 13 and internetx:php5:extensions / php5-sphinx
[-] | Added | php-pecl-sphinx.changes |
x 1
2 +------------------------------------------------------------------- 3 +Fri Apr 22 07:03:44 UTC 2016 - cs@linux-administrator.com 4 + 5 +- update to 1.4.0-dev 6 + 7 +------------------------------------------------------------------- 8 +Tue Aug 4 08:46:47 UTC 2015 - cs@linux-administrator.com 9 + 10 +- update to release 1.3.3 11 + 12 +------------------------------------------------------------------- 13 +Tue May 13 18:50:53 UTC 2014 - cs@linux-administrator.com 14 + 15 +- update to release 1.3.2 16 + 17 |
||
[+] | Deleted | php5-sphinx.changes ^ |
@@ -1,10 +0,0 @@ -------------------------------------------------------------------- -Tue Aug 4 08:46:47 UTC 2015 - cs@linux-administrator.com - -- update to release 1.3.3 - -------------------------------------------------------------------- -Tue May 13 18:50:53 UTC 2014 - cs@linux-administrator.com - -- update to release 1.3.2 - | ||
[-] | Added | php-pecl-sphinx.spec ^ |
156 1
2 +%global __pecl %{_bindir}/pecl 3 + 4 +%global php_zendabiver %((echo 0; php -i 2>/dev/null | sed -n 's/^PHP Extension => //p') | tail -1) 5 +%global php_version %((echo 0; php-config --version 2>/dev/null) | tail -1) 6 +%global php_pkg_version %((echo 0; rpm -q php-devel --qf '%{version}-%{release}' 2>/dev/null) | tail -1) 7 +%global basepkg php 8 +%global pecl_name sphinx 9 +%global with_zts 0%{?__ztsphp:1} 10 + 11 +# norootforbuild 12 +%define pkg_name sphinx 13 +%define pkg_version 1.3.99.1 14 +%define php_version %(php-config --version 2>/dev/null) 15 +# 16 +Name: php-pecl-sphinx 17 +Version: %{pkg_version} 18 +Release: 1 19 +# 20 +License: PHP 21 +Group: Productivity/Networking/Web/Servers 22 +# 23 +BuildRoot: %{_tmppath}/%{pkg_name}-%{version}-build 24 +BuildRequires: php-devel libsphinxclient-devel gcc gcc-c++ 25 +#Requires: php = %{php_pkg_version} 26 +Requires: php(zend-abi) = %{php_zend_api} 27 +Requires: php(api) = %{php_core_api} 28 +# 29 +URL: http://pecl.php.net/ 30 +Source: http://pecl.php.net/package/%{pkg_name}/%{pkg_name}-%{version}.tgz 31 +Source1: package.xml 32 +Summary: This extension provides bindings for libsphinxclient, client library for Sphinx 33 +Provides: php-pecl(%{pecl_name}) = %{version} 34 + 35 +Requires(post): %{__pecl} 36 +Requires(postun): %{__pecl} 37 + 38 +%description 39 +This extension provides bindings for libsphinxclient, client library for Sphinx. 40 + 41 +Authors: 42 +--------- 43 + 44 + Antony Dovgal 45 + 46 +%prep 47 +%setup -q -c -n %{pkg_name}-%{version} 48 +cp %{S:1} . 49 +%if %{with_zts} 50 +cp -r %{pecl_name}-%{version} %{pecl_name}-%{version}-zts 51 +%endif 52 + 53 +%build 54 +pushd %{pecl_name}-%{version} 55 +%{_bindir}/phpize 56 +%configure --with-sphinx=%{_prefix} --with-php-config=%{_bindir}/php-config 57 +%{__make} %{?_smp_mflags} 58 +popd 59 + 60 +%if %{with_zts} 61 +pushd %{pecl_name}-%{version}-zts 62 +%{_bindir}/zts-phpize 63 +%configure --with-sphinx=%{_prefix} --with-php-config=%{_bindir}/zts-php-config 64 +%{__make} %{?_smp_mflags} 65 +popd 66 +%endif 67 + 68 +%install 69 +%{__rm} -rf %{buildroot} 70 + 71 +pushd %{pecl_name}-%{version} 72 +%{__make} install INSTALL_ROOT=%{buildroot} 73 + 74 +popd 75 + 76 +%if %{with_zts} 77 +pushd %{pecl_name}-%{version}-zts 78 +%{__make} install INSTALL_ROOT=%{buildroot} 79 +popd 80 + 81 +%endif 82 + 83 +# Install the package XML file 84 +%{__mkdir_p} %{buildroot}%{pecl_xmldir} 85 +%{__install} -m 644 package.xml %{buildroot}%{pecl_xmldir}/%{name}.xml 86 + 87 +# Drop in the bit of configuration 88 +%{__mkdir_p} %{buildroot}%{php_inidir} 89 +%{__cat} > %{buildroot}%{php_inidir}/sphinx.ini << 'EOF' 90 +; Enable sphinx extension module 91 +extension = sphinx.so 92 +EOF 93 + 94 +%if %{with_zts} 95 +%{__mkdir_p} %{buildroot}%{php_ztsinidir} 96 +%{__cp} %{buildroot}%{php_inidir}/sphinx.ini %{buildroot}%{php_ztsinidir}/sphinx.ini 97 +%endif 98 + 99 +%check 100 +pushd %{pecl_name}-%{version} 101 +TEST_PHP_EXECUTABLE=$(which php) php run-tests.php \ 102 + -n -q -d extension_dir=modules \ 103 + -d extension=sphinx.so 104 +popd 105 + 106 +%if %{with_zts} 107 +pushd %{pecl_name}-%{version}-zts 108 +TEST_PHP_EXECUTABLE=$(which zts-php) zts-php run-tests.php \ 109 + -n -q -d extension_dir=modules \ 110 + -d extension=sphinx.so 111 +popd 112 +%endif 113 + 114 +%if 0%{?pecl_install:1} 115 +%post 116 +%{pecl_install} %{pecl_xmldir}/%{name}.xml >/dev/null || : 117 +%endif 118 + 119 +%if 0%{?pecl_uninstall:1} 120 +%postun 121 +if [ $1 -eq 0 ] ; then 122 + %{pecl_uninstall} %{pecl_name} >/dev/null || : 123 +fi 124 +%endif 125 + 126 +%clean 127 +%{__rm} -rf %{buildroot} 128 + 129 +%files 130 +%defattr(-,root,root,-) 131 +%config(noreplace) %{php_inidir}/sphinx.ini 132 +%{php_extdir}/sphinx.so 133 +%{pecl_xmldir}/%{name}.xml 134 + 135 +%if %{with_zts} 136 +%config(noreplace) %{php_ztsinidir}/sphinx.ini 137 +%{php_ztsextdir}/sphinx.so 138 +%endif 139 + 140 +%changelog 141 +* Thu Apr 04 2013 Carsten Schoene <cs@linux-administrator.com> - 1.3.0-1 142 +- update to release 1.3.0 143 + 144 +* Sun Apr 09 2012 Carsten Schoene <cs@linux-administrator.com> - 1.2.0-1 145 +- update to release 1.2.0 146 + 147 +* Tue Jan 12 2010 Carsten Schoene <cs@linux-administrator.com> - 1.0.3-0 148 +- update to release 1.0.3 149 + - Added support for open(), close(), status() and setOverride() available in sphinx 0.9.9 new API 150 + 151 +* Sun Dec 20 2009 Carsten Schoene <cs@linux-administrator.com> - 1.0.2-0 152 +- update to release 1.0.2 153 + 154 +* Sat Jan 31 2009 Carsten Schoene <cs@linux-administrator.com> 155 +- initial build version 1.0.0 156 |
||
[+] | Deleted | php5-sphinx.spec ^ |
@@ -1,87 +0,0 @@ -# norootforbuild -%define pkg_name sphinx -%define pkg_version 1.3.3 -%define php_version %(php-config --version 2>/dev/null) -# -Name: php5-sphinx -Version: %{pkg_version} -Release: 1 -# -License: PHP -Group: Productivity/Networking/Web/Servers -# -BuildRoot: %{_tmppath}/%{pkg_name}-%{version}-build -BuildRequires: php5-devel libsphinxclient-devel gcc gcc-c++ -Requires: php5 = %{php_version} -# -URL: http://pecl.php.net/ -Source: http://pecl.php.net/package/%{pkg_name}/%{pkg_name}-%{version}.tgz -Summary: This extension provides bindings for libsphinxclient, client library for Sphinx - -%description -This extension provides bindings for libsphinxclient, client library for Sphinx. - -Authors: ---------- - - Antony Dovgal - -%debug_package - -%prep -%setup -n %{pkg_name}-%{version} - -%{__mkdir} %{name} - -%build -/usr/bin/phpize -pushd %{name} - -CFLAGS="%{optflags} -fno-strict-aliasing" -CXXFLAGS="%{optflags} -fno-strict-aliasing" -%if 0%{?suse_version} > 1000 -CFLAGS="$CFLAGS -fstack-protector" -CXXFLAGS="$CXXFLAGS -fstack-protector" -%endif - -export CFLAGS -export CXXFLAGS - -../configure --with-sphinx=%{_usr} --with-libdir=%{_lib} - -%{__make} %{?jobs:-j%jobs} -popd - -%install -%makeinstall -C %{name} INSTALL_ROOT=%{buildroot} -%{__mkdir} -p %{buildroot}%{_sysconfdir}/php5/conf.d -echo "; comment out next line to disable sphinx extension in php" > %{buildroot}%{_sysconfdir}/php5/conf.d/sphinx.ini -echo "extension = sphinx.so" >> %{buildroot}%{_sysconfdir}/php5/conf.d/sphinx.ini - - -%clean -%{__rm} -rf %{buildroot} - -%files -%defattr(-,root,root,-) -%{_libdir}/php5/extensions/sphinx.so -%config(noreplace) %{_sysconfdir}/php5/conf.d/sphinx.ini - -%doc CREDITS - -%changelog -* Thu Apr 04 2013 Carsten Schoene <cs@linux-administrator.com> - 1.3.0-1 -- update to release 1.3.0 - -* Sun Apr 09 2012 Carsten Schoene <cs@linux-administrator.com> - 1.2.0-1 -- update to release 1.2.0 - -* Tue Jan 12 2010 Carsten Schoene <cs@linux-administrator.com> - 1.0.3-0 -- update to release 1.0.3 - - Added support for open(), close(), status() and setOverride() available in sphinx 0.9.9 new API - -* Sun Dec 20 2009 Carsten Schoene <cs@linux-administrator.com> - 1.0.2-0 -- update to release 1.0.2 - -* Sat Jan 31 2009 Carsten Schoene <cs@linux-administrator.com> -- initial build version 1.0.0 | ||
[+] | Added | package.xml ^ |
@@ -0,0 +1,237 @@ +<?xml version="1.0" encoding="UTF-8"?> +<package packagerversion="1.9.5" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd"> + <name>sphinx</name> + <channel>pecl.php.net</channel> + <summary>Client extension for Sphinx - opensource SQL full-text search engine</summary> + <description>This extension provides bindings for libsphinxclient, client library for Sphinx.</description> + <lead> + <name>Antony Dovgal</name> + <user>tony2001</user> + <email>tony2001@php.net</email> + <active>yes</active> + </lead> + <lead> + <name>Alexey Romanenko</name> + <user>santiago</user> + <email>santiago739@gmail.com</email> + <active>yes</active> + </lead> + <date>2015-05-21</date> + <time>15:33:48</time> + <version> + <release>1.3.99.1</release> + <api>1.3.99.1</api> + </version> + <stability> + <release>unstable</release> + <api>unstable</api> + </stability> + <license uri="http://www.php.net/license">PHP</license> + <notes> +- PHP7 support + </notes> + <contents> + <dir name="/"> + </dir> + </contents> + <dependencies> + <required> + <php> + <min>7.0.0</min> + <max>7.1.0</max> + <exclude>6.0.0</exclude> + </php> + <pearinstaller> + <min>1.4.0b1</min> + </pearinstaller> + </required> + </dependencies> + <providesextension>sphinx</providesextension> + <extsrcrelease> + <configureoption default="autodetect" name="with-sphinx" prompt="Please provide the installation prefix of libsphinxclient" /> + </extsrcrelease> + <changelog> + <release> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <version> + <release>1.3.2</release> + <api>1.3.2</api> + </version> + <date>2014-05-06</date> + <notes> +- Fixed build with older libsphinxclient versions (Dmitry Saprykin) +- Added LICENSE to the package. + </notes> + </release> + <release> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <version> + <release>1.3.1</release> + <api>1.3.1</api> + </version> + <date>2014-05-06</date> + <notes> +- Fixed bug #67216 (segfault on setGroupBy()) (Dmitry Saprykin) +- Fixed bug #66272 (Some constants are not defined) + </notes> + </release> + <release> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <version> + <release>1.3.0</release> + <api>1.3.0</api> + </version> + <date>2013-04-04</date> + <notes> +- Fixed setRankingMode's proto and add new ranking mode constants (patch by Michael Squires) +- Fixed segfault when reading object properties. +- Fixed bug #62026 (Second param in setRankingMode should be optional) + </notes> + </release> + <release> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <version> + <release>1.2.0</release> + <api>1.2.0</api> + </version> + <date>2012-04-03</date> + <notes> +- Added mva support to updateAttributes(). +- Fixed build with 5_4. +- Fixed bug #61392 (build failure with new version of libsphinxclient) + </notes> + </release> + <release> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <version> + <release>1.1.0</release> + <api>1.1.0</api> + </version> + <date>2010-09-17</date> + <notes> +- Added support for new API in sphinx 1.10 + - Fixed PECL bug #18325 (support 1.10-beta string attributes) + - Fixed PECL bug #17558 (time taken in search result was incorrect) + </notes> + </release> + <release> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <version> + <release>1.0.4</release> + <api>1.0.4</api> + </version> + <date>2010-02-26</date> + <notes> +- Fixed PECL bug #17007 (incorrect query causes SEGFAULT) + </notes> + </release> + <release> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <version> + <release>1.0.3</release> + <api>1.0.3</api> + </version> + <date>2010-01-12</date> + <notes> +- Added support for open(), close(), status() and setOverride() available in sphinx 0.9.9 new API + </notes> + </release> + <release> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <version> + <release>1.0.2</release> + <api>1.0.2</api> + </version> + <date>2009-12-03</date> + <notes> +- Fixed crash when extending class doesn't call parent constructor. + </notes> + </release> + <release> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <version> + <release>1.0.1</release> + <api>1.0.1</api> + </version> + <date>2009-11-03</date> + <notes> +- Fixed build failure with PHP 5.1.x. +- Added support for setSelect(), available in sphinx 0.9.9 new API (patch by Olivier Poitrey) + </notes> + </release> + <release> + <stability> + <release>stable</release> + <api>stable</api> + </stability> + <version> + <release>1.0.0</release> + <api>1.0.0</api> + </version> + <date>2009-01-29</date> + <notes> | ||
[+] | Deleted | sphinx-1.0.0.tgz/sphinx-1.0.0/CREDITS ^ |
@@ -1,2 +0,0 @@ -Sphinx client extension for PHP -Antony Dovgal | ||
[+] | Deleted | sphinx-1.0.0.tgz/sphinx-1.0.0/config.m4 ^ |
@@ -1,50 +0,0 @@ -dnl $Id: config.m4,v 1.2 2008/10/31 14:04:51 tony2001 Exp $ - -PHP_ARG_WITH(sphinx, for sphinx support, -[ --with-sphinx Include sphinx support]) - -if test "$PHP_SPHINX" != "no"; then - - SEARCH_PATH="/usr/local /usr /local /opt" - SEARCH_FOR="/include/sphinxclient.h" - - if test "$PHP_SPHINX" = "yes"; then - AC_MSG_CHECKING([for libsphinxclient headers in default path]) - for i in $SEARCH_PATH ; do - if test -r $i/$SEARCH_FOR; then - SPHINX_DIR=$i - AC_MSG_RESULT(found in $i) - fi - done - else - AC_MSG_CHECKING([for libsphinxclient headers in $PHP_SPHINX]) - if test -r $PHP_SPHINX/$SEARCH_FOR; then - SPHINX_DIR=$PHP_SPHINX - AC_MSG_RESULT([found]) - fi - fi - - if test -z "$SPHINX_DIR"; then - AC_MSG_RESULT([not found]) - AC_MSG_ERROR([Cannot find libsphinxclient headers]) - fi - - PHP_ADD_INCLUDE($SPHINX_DIR/include) - - LIBNAME=sphinxclient - LIBSYMBOL=sphinx_create - - PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL, - [ - PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $SPHINX_DIR/$PHP_LIBDIR, SPHINX_SHARED_LIBADD) - AC_DEFINE(HAVE_SPHINXLIB,1,[ ]) - ],[ - AC_MSG_ERROR([wrong libsphinxclient version or lib not found]) - ],[ - -L$SPHINX_DIR/$PHP_LIBDIR -lm - ]) - - PHP_SUBST(SPHINX_SHARED_LIBADD) - - PHP_NEW_EXTENSION(sphinx, sphinx.c, $ext_shared) -fi | ||
[+] | Deleted | sphinx-1.0.0.tgz/sphinx-1.0.0/config.w32 ^ |
@@ -1,13 +0,0 @@ -// $Id: config.w32,v 1.1 2008/07/16 07:32:49 tony2001 Exp $ -// vim:ft=javascript - -ARG_WITH("sphinx", "for sphinx support", "yes"); - -if (PHP_SPHINX == "yes") { - if (CHECK_LIB("libsphinxclient.lib", "sphinx_create") && - CHECK_HEADER_ADD_INCLUDE("sphinxclient.h", "CFLAGS_SPHINX")) { - - EXTENSION("sphinx", "sphinx.c"); - } -} - | ||
[+] | Deleted | sphinx-1.0.0.tgz/sphinx-1.0.0/php_sphinx.h ^ |
@@ -1,46 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 5 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2008 The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.01 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_01.txt | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Author: Antony Dovgal <tony at daylessday.org> | - | Based on Sphinx PHP API by Andrew Aksyonoff <shodan at shodan.ru> | - +----------------------------------------------------------------------+ -*/ - -/* $Id: php_sphinx.h,v 1.5 2009/01/28 17:11:02 tony2001 Exp $ */ - -#ifndef PHP_SPHINX_H -#define PHP_SPHINX_H - -extern zend_module_entry sphinx_module_entry; -#define phpext_sphinx_ptr &sphinx_module_entry - -#ifdef ZTS -#include "TSRM.h" -#endif - -PHP_MINIT_FUNCTION(sphinx); -PHP_MINFO_FUNCTION(sphinx); - -#define PHP_SPHINX_VERSION "1.0.0" - -#endif /* PHP_SPHINX_H */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ | ||
[+] | Deleted | sphinx-1.0.0.tgz/sphinx-1.0.0/sphinx.c ^ |
@@ -1,1610 +0,0 @@ -/* - +----------------------------------------------------------------------+ - | PHP Version 5 | - +----------------------------------------------------------------------+ - | Copyright (c) 1997-2008 The PHP Group | - +----------------------------------------------------------------------+ - | This source file is subject to version 3.01 of the PHP license, | - | that is bundled with this package in the file LICENSE, and is | - | available through the world-wide-web at the following url: | - | http://www.php.net/license/3_01.txt | - | If you did not receive a copy of the PHP license and are unable to | - | obtain it through the world-wide-web, please send a note to | - | license@php.net so we can mail you a copy immediately. | - +----------------------------------------------------------------------+ - | Author: Antony Dovgal <tony at daylessday.org> | - | Based on Sphinx PHP API by Andrew Aksyonoff <shodan at shodan.ru> | - +----------------------------------------------------------------------+ -*/ - -/* $Id: sphinx.c,v 1.17 2008/11/21 15:23:05 tony2001 Exp $ */ - -#ifdef HAVE_CONFIG_H -#include "config.h" -#endif - -#include "php.h" -#include "php_ini.h" -#include "ext/standard/info.h" -#include "ext/standard/file.h" -#include "zend_operators.h" -#include "php_sphinx.h" - -#include <sphinxclient.h> - -static zend_class_entry *ce_sphinx_client; - -static zend_object_handlers php_sphinx_client_handlers; -static zend_object_handlers cannot_be_cloned; - -typedef struct _php_sphinx_client { - zend_object std; - sphinx_client *sphinx; - zend_bool array_result; -} php_sphinx_client; - -#ifdef COMPILE_DL_SPHINX -ZEND_GET_MODULE(sphinx) -#endif - -#define SPHINX_CONST(name) REGISTER_LONG_CONSTANT(#name, name, CONST_CS | CONST_PERSISTENT) - -static void php_sphinx_client_obj_dtor(void *object TSRMLS_DC) /* {{{ */ -{ - php_sphinx_client *c = (php_sphinx_client *)object; - - sphinx_destroy(c->sphinx); - zend_object_std_dtor(&c->std TSRMLS_CC); - efree(c); -} -/* }}} */ - -static zend_object_value php_sphinx_client_new(zend_class_entry *ce TSRMLS_DC) /* {{{ */ -{ - php_sphinx_client *c; - zend_object_value retval; - - c = ecalloc(1, sizeof(*c)); - zend_object_std_init(&c->std, ce TSRMLS_CC); - - retval.handle = zend_objects_store_put(c, (zend_objects_store_dtor_t)zend_objects_destroy_object, php_sphinx_client_obj_dtor, NULL TSRMLS_CC); - retval.handlers = &php_sphinx_client_handlers; - return retval; -} -/* }}} */ - -static zval *php_sphinx_client_read_property(zval *object, zval *member, int type TSRMLS_DC) /* {{{ */ -{ - php_sphinx_client *c; - zval tmp_member; - zval *retval; - zend_object_handlers *std_hnd; - - c = (php_sphinx_client *)zend_object_store_get_object(object TSRMLS_CC); - - if (member->type != IS_STRING) { - tmp_member = *member; - zval_copy_ctor(&tmp_member); - convert_to_string(&tmp_member); - member = &tmp_member; - } - - /* XXX we can either create retval ourselves (for custom properties) or use standard handlers */ - - std_hnd = zend_get_std_object_handlers(); - retval = std_hnd->read_property(object, member, type TSRMLS_CC); - - if (member == &tmp_member) { - zval_dtor(member); - } - return retval; -} -/* }}} */ - -static HashTable *php_sphinx_client_get_properties(zval *object TSRMLS_DC) /* {{{ */ -{ - php_sphinx_client *c; - const char *warning, *error; - zval *tmp; - - c = (php_sphinx_client *)zend_objects_get_address(object TSRMLS_CC); - - error = sphinx_error(c->sphinx); - MAKE_STD_ZVAL(tmp); - ZVAL_STRING(tmp, (char *)error, 1); - zend_hash_update(c->std.properties, "error", sizeof("error"), (void *)&tmp, sizeof(zval *), NULL); - - warning = sphinx_warning(c->sphinx); - MAKE_STD_ZVAL(tmp); - ZVAL_STRING(tmp, (char *)warning, 1); - zend_hash_update(c->std.properties, "warning", sizeof("warning"), (void *)&tmp, sizeof(zval *), NULL); - return c->std.properties; -} -/* }}} */ - -#ifdef TONY_200807015 -static inline void php_sphinx_error(php_sphinx_client *c TSRMLS_DC) /* {{{ */ -{ - const char *err; - - err = sphinx_error(c->sphinx); - if (!err || err[0] == '\0') { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "unknown error"); - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", err); - } -} -/* }}} */ -#endif - -static void php_sphinx_result_to_array(php_sphinx_client *c, sphinx_result *result, zval **array TSRMLS_DC) /* {{{ */ -{ - zval *tmp, *tmp_element, *sub_element, *sub_sub_element; - int i, j; - - array_init(*array); - - /* error */ - if (!result->error) { - add_assoc_string_ex(*array, "error", sizeof("error"), "", 1); - } else { - add_assoc_string_ex(*array, "error", sizeof("error"), (char *)(result->error), 1); - } - - /* warning */ - if (!result->warning) { - add_assoc_string_ex(*array, "warning", sizeof("warning"), "", 1); - } else { - add_assoc_string_ex(*array, "warning", sizeof("warning"), (char *)result->warning, 1); - } - - /* status */ - add_assoc_long_ex(*array, "status", sizeof("status"), result->status); - - /* fields */ - MAKE_STD_ZVAL(tmp); - array_init(tmp); - - for (i = 0; i < result->num_fields; i++) { - add_next_index_string(tmp, result->fields[i], 1); - } - add_assoc_zval_ex(*array, "fields", sizeof("fields"), tmp); - - /* attrs */ - MAKE_STD_ZVAL(tmp); - array_init(tmp); - - for (i = 0; i < result->num_attrs; i++) { -#if SIZEOF_LONG == 8 - add_assoc_long_ex(tmp, result->attr_names[i], strlen(result->attr_names[i]) + 1, result->attr_types[i]); -#else - double float_value; - char buf[128]; - - float_value = (double)result->attr_types[i]; - slprintf(buf, sizeof(buf), "%.0f", float_value); - add_assoc_string_ex(tmp, result->attr_names[i], strlen(result->attr_names[i]) + 1, buf, 1); -#endif - } - add_assoc_zval_ex(*array, "attrs", sizeof("attrs"), tmp); - - /* matches */ - if (result->num_matches) { - MAKE_STD_ZVAL(tmp); - array_init(tmp); - - for (i = 0; i < result->num_matches; i++) { - MAKE_STD_ZVAL(tmp_element); - array_init(tmp_element); - - if (c->array_result) { - /* id */ -#if SIZEOF_LONG == 8 - add_assoc_long_ex(tmp_element, "id", sizeof("id"), sphinx_get_id(result, i)); -#else - double float_id; - char buf[128]; - - float_id = (double)sphinx_get_id(result, i); - slprintf(buf, sizeof(buf), "%.0f", float_id); - add_assoc_string_ex(tmp_element, "id", sizeof("id"), buf, 1); -#endif - } - - /* weight */ - add_assoc_long_ex(tmp_element, "weight", sizeof("weight"), sphinx_get_weight(result, i)); - - /* attrs */ - MAKE_STD_ZVAL(sub_element); - array_init(sub_element); - - for (j = 0; j < result->num_attrs; j++) { - double float_value; - char buf[128]; - - MAKE_STD_ZVAL(sub_sub_element); - - switch(result->attr_types[j]) { - case SPH_ATTR_MULTI | SPH_ATTR_INTEGER: - { - int k; - unsigned int *mva = sphinx_get_mva(result, i, j); - unsigned int tmp, num; - - array_init(sub_sub_element); - - if (!mva) { - break; - } - - memcpy(&num, mva, sizeof(unsigned int)); - - for (k = 1; k <= num; k++) { - mva++; - memcpy(&tmp, mva, sizeof(unsigned int)); -#if SIZEOF_LONG == 8 - add_next_index_long(sub_sub_element, tmp); -#else - float_value = (double)tmp; - slprintf(buf, sizeof(buf), "%.0f", float_value); - add_next_index_string(sub_sub_element, buf, 1); -#endif - } - } break; - - case SPH_ATTR_FLOAT: - ZVAL_DOUBLE(sub_sub_element, sphinx_get_float(result, i, j)); - break; - default: -#if SIZEOF_LONG == 8 - ZVAL_LONG(sub_sub_element, sphinx_get_int(result, i, j)); -#else - float_value = (double)sphinx_get_int(result, i, j); - slprintf(buf, sizeof(buf), "%.0f", float_value); - ZVAL_STRING(sub_sub_element, buf, 1); -#endif - break; - } - - add_assoc_zval(sub_element, result->attr_names[j], sub_sub_element); - } - - add_assoc_zval_ex(tmp_element, "attrs", sizeof("attrs"), sub_element); - - if (c->array_result) { - add_next_index_zval(tmp, tmp_element); - } else { -#if SIZEOF_LONG == 8 - add_index_zval(tmp, sphinx_get_id(result, i), tmp_element); -#else - char buf[128]; - double float_id; - int buf_len; - - float_id = (double)sphinx_get_id(result, i); - buf_len = slprintf(buf, sizeof(buf), "%.0f", float_id); - add_assoc_zval_ex(tmp, buf, buf_len + 1, tmp_element); -#endif - } - } - - add_assoc_zval_ex(*array, "matches", sizeof("matches"), tmp); - } - - /* total */ - add_assoc_long_ex(*array, "total", sizeof("total"), result->total); - - /* total_found */ - add_assoc_long_ex(*array, "total_found", sizeof("total_found"), result->total_found); - - /* time */ - add_assoc_double_ex(*array, "time", sizeof("time"), result->time_msec/1000); - - /* words */ - if (result->num_words) { - MAKE_STD_ZVAL(tmp); - array_init(tmp); - for (i = 0; i < result->num_words; i++) { - MAKE_STD_ZVAL(sub_element); - array_init(sub_element); - - add_assoc_long_ex(sub_element, "docs", sizeof("docs"), result->words[i].docs); - add_assoc_long_ex(sub_element, "hits", sizeof("hits"), result->words[i].hits); - add_assoc_zval_ex(tmp, (char *)result->words[i].word, strlen(result->words[i].word) + 1, sub_element); - } - add_assoc_zval_ex(*array, "words", sizeof("words"), tmp); - } -} -/* }}} */ - - -/* {{{ proto void SphinxClient::__construct() */ -static PHP_METHOD(SphinxClient, __construct) -{ - php_sphinx_client *c; - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - if (c->sphinx) { - /* called __construct() twice, bail out */ - return; - } - - c->sphinx = sphinx_create(1 /* copy string args */); - - sphinx_set_connect_timeout(c->sphinx, FG(default_socket_timeout)); -} -/* }}} */ - -/* {{{ proto bool SphinxClient::setServer(string server, int port) */ -static PHP_METHOD(SphinxClient, setServer) -{ - php_sphinx_client *c; - long port; - char *server; - int server_len, res; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl", &server, &server_len, &port) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - res = sphinx_set_server(c->sphinx, server, (int)port); - if (!res) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool SphinxClient::setLimits(int offset, int limit[, int max_matches[, int cutoff]]) */ -static PHP_METHOD(SphinxClient, setLimits) -{ - php_sphinx_client *c; - long offset, limit, max_matches = 0, cutoff = 0; - int res; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll|ll", &offset, &limit, &max_matches, &cutoff) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - res = sphinx_set_limits(c->sphinx, (int)offset, (int)limit, (int)max_matches, (int)cutoff); - if (!res) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool SphinxClient::setMatchMode(int mode) */ -static PHP_METHOD(SphinxClient, setMatchMode) -{ - php_sphinx_client *c; - long mode; - int res; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &mode) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - res = sphinx_set_match_mode(c->sphinx, mode); - if (!res) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool SphinxClient::setIndexWeights(array weights) */ -static PHP_METHOD(SphinxClient, setIndexWeights) -{ - php_sphinx_client *c; - zval *weights, **item; - int num_weights, res = 0, i; - int *index_weights; - char **index_names; - char *string_key; - unsigned int string_key_len; - unsigned long int num_key; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &weights) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - num_weights = zend_hash_num_elements(Z_ARRVAL_P(weights)); - if (!num_weights) { - /* check for empty array and return false right away */ - RETURN_FALSE; - } - - index_names = safe_emalloc(num_weights, sizeof(char *), 0); - index_weights = safe_emalloc(num_weights, sizeof(int), 0); - - /* reset num_weights, we'll reuse it count _real_ number of entries */ - num_weights = 0; - - for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(weights)); - zend_hash_get_current_data(Z_ARRVAL_P(weights), (void **)&item) != FAILURE; - zend_hash_move_forward(Z_ARRVAL_P(weights))) { - - if (zend_hash_get_current_key_ex(Z_ARRVAL_P(weights), &string_key, &string_key_len, &num_key, 0, NULL) != HASH_KEY_IS_STRING) { - /* if the key is not string.. well.. you're screwed */ - break; - } - - convert_to_long_ex(item); - - index_names[num_weights] = estrndup(string_key, string_key_len); - index_weights[num_weights] = Z_LVAL_PP(item); - - num_weights++; - } - - if (num_weights) { - res = sphinx_set_index_weights(c->sphinx, num_weights, (const char **)index_names, index_weights); - } - - for (i = 0; i != num_weights; i++) { - efree(index_names[i]); - } - efree(index_names); - efree(index_weights); - - if (!res) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool SphinxClient::setIDRange(int min, int max) */ -static PHP_METHOD(SphinxClient, setIDRange) -{ - php_sphinx_client *c; - long min, max; - int res; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ll", &min, &max) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - res = sphinx_set_id_range(c->sphinx, (sphinx_uint64_t)min, (sphinx_uint64_t)max); - if (!res) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool SphinxClient::setFilter(string attribute, array values[, bool exclude]) */ -static PHP_METHOD(SphinxClient, setFilter) -{ - php_sphinx_client *c; - zval *values, **item; - char *attribute; - int attribute_len, num_values, i = 0, res; - zend_bool exclude = 0; - sphinx_uint64_t *u_values; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sa|b", &attribute, &attribute_len, &values, &exclude) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - num_values = zend_hash_num_elements(Z_ARRVAL_P(values)); - if (!num_values) { - RETURN_FALSE; - } - - u_values = safe_emalloc(num_values, sizeof(sphinx_uint64_t), 0); - - for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(values)); - zend_hash_get_current_data(Z_ARRVAL_P(values), (void **) &item) != FAILURE; - zend_hash_move_forward(Z_ARRVAL_P(values))) { - - convert_to_double_ex(item); - u_values[i] = (sphinx_uint64_t)Z_DVAL_PP(item); - i++; - } - - res = sphinx_add_filter(c->sphinx, attribute, num_values, u_values, exclude ? 1 : 0); - efree(u_values); - - if (!res) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool SphinxClient::setFilterRange(string attribute, int min, int max[, bool exclude]) */ -static PHP_METHOD(SphinxClient, setFilterRange) -{ - php_sphinx_client *c; - char *attribute; - int attribute_len, res; - long min, max; - zend_bool exclude = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sll|b", &attribute, &attribute_len, &min, &max, &exclude ) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - res = sphinx_add_filter_range(c->sphinx, attribute, min, max, exclude); - - if (!res) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool SphinxClient::setFilterFloatRange(string attribute, float min, float max[, bool exclude]) */ -static PHP_METHOD(SphinxClient, setFilterFloatRange) -{ - php_sphinx_client *c; - char *attribute; - int attribute_len, res; - double min, max; - zend_bool exclude = 0; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sdd|b", &attribute, &attribute_len, &min, &max, &exclude) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - res = sphinx_add_filter_float_range(c->sphinx, attribute, min, max, exclude); - - if (!res) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool SphinxClient::setGeoAnchor(string attrlat, string attrlong, float latitude, float longitude) */ -static PHP_METHOD(SphinxClient, setGeoAnchor) -{ - php_sphinx_client *c; - char *attrlat, *attrlong; - int attrlat_len, attrlong_len, res; - double latitude, longitude; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssdd", &attrlat, &attrlat_len, &attrlong, &attrlong_len, &latitude, &longitude) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - res = sphinx_set_geoanchor(c->sphinx, attrlat, attrlong, latitude, longitude); - - if (!res) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool SphinxClient::setGroupBy(string attribute, int func[, string groupsort]) */ -static PHP_METHOD(SphinxClient, setGroupBy) -{ - php_sphinx_client *c; - char *attribute, *groupsort = NULL; - int attribute_len, groupsort_len, func, res; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sl|s", &attribute, &attribute_len, &func, &groupsort, &groupsort_len) == FAILURE) { - return; - } - - if (groupsort == NULL) { - groupsort = "@group desc"; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - res = sphinx_set_groupby(c->sphinx, attribute, func, groupsort); - - if (!res) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool SphinxClient::setGroupDistinct(string attribute) */ -static PHP_METHOD(SphinxClient, setGroupDistinct) -{ - php_sphinx_client *c; - char *attribute; - int attribute_len, res; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &attribute, &attribute_len) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - res = sphinx_set_groupby_distinct(c->sphinx, attribute); - - if (!res) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool SphinxClient::setRetries(int count[, int delay]) */ -static PHP_METHOD(SphinxClient, setRetries) -{ - php_sphinx_client *c; - long count, delay = 0; - int res; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &count, &delay) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - res = sphinx_set_retries(c->sphinx, (int)count, (int)delay); - - if (!res) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool SphinxClient::setMaxQueryTime(int qtime) */ -static PHP_METHOD(SphinxClient, setMaxQueryTime) -{ - php_sphinx_client *c; - long qtime; - int res; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &qtime) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - res = sphinx_set_max_query_time(c->sphinx, (int)qtime); - - if (!res) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool SphinxClient::setRankingMode(int ranker) */ -static PHP_METHOD(SphinxClient, setRankingMode) -{ - php_sphinx_client *c; - long ranker; - int res; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &ranker) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - res = sphinx_set_ranking_mode(c->sphinx, (int)ranker); - - if (!res) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool SphinxClient::setFieldWeights(array weights) */ -static PHP_METHOD(SphinxClient, setFieldWeights) -{ - php_sphinx_client *c; - zval *weights, **item; - int num_weights, res = 0, i; - int *field_weights; - char **field_names; - char *string_key; - unsigned int string_key_len; - unsigned long int num_key; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a", &weights) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - num_weights = zend_hash_num_elements(Z_ARRVAL_P(weights)); - if (!num_weights) { - /* check for empty array and return false right away */ - RETURN_FALSE; - } - - field_names = safe_emalloc(num_weights, sizeof(char *), 0); - field_weights = safe_emalloc(num_weights, sizeof(int), 0); - - /* reset num_weights, we'll reuse it count _real_ number of entries */ - num_weights = 0; - - for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(weights)); - zend_hash_get_current_data(Z_ARRVAL_P(weights), (void **)&item) != FAILURE; - zend_hash_move_forward(Z_ARRVAL_P(weights))) { - - if (zend_hash_get_current_key_ex(Z_ARRVAL_P(weights), &string_key, &string_key_len, &num_key, 0, NULL) != HASH_KEY_IS_STRING) { - /* if the key is not string.. well.. you're screwed */ - break; - } - - convert_to_long_ex(item); - - field_names[num_weights] = estrndup(string_key, string_key_len); - field_weights[num_weights] = Z_LVAL_PP(item); - - num_weights++; - } - - if (num_weights) { - res = sphinx_set_field_weights(c->sphinx, num_weights, (const char **) field_names, field_weights); - } - - for (i = 0; i != num_weights; i++) { - efree(field_names[i]); - } - efree(field_names); - efree(field_weights); - - if (!res) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool SphinxClient::setSortMode(int mode[, string sortby]) */ -static PHP_METHOD(SphinxClient, setSortMode) -{ - php_sphinx_client *c; - long mode; - char *sortby = NULL; - int sortby_len, res; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|s", &mode, &sortby, &sortby_len) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - res = sphinx_set_sort_mode(c->sphinx, (int)mode, sortby); - - if (!res) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool SphinxClient::setConnectTimeout(float timeout) */ -static PHP_METHOD(SphinxClient, setConnectTimeout) -{ - php_sphinx_client *c; - double timeout; - int res; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "d", &timeout) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - res = sphinx_set_connect_timeout(c->sphinx, timeout); - - if (!res) { - RETURN_FALSE; - } - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto bool SphinxClient::setArrayResult(bool array_result) */ -static PHP_METHOD(SphinxClient, setArrayResult) -{ - php_sphinx_client *c; - zend_bool array_result; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &array_result) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - c->array_result = array_result; - RETURN_TRUE; -} -/* }}} */ - -/* {{{ proto int SphinxClient::updateAttributes(string index, array attributes, array values) */ -static PHP_METHOD(SphinxClient, updateAttributes) -{ - php_sphinx_client *c; - zval *attributes, *values, **item; - char *index; - const char **attrs; - int index_len, attrs_num, values_num, a = 0, i = 0, j = 0; - int res; - sphinx_uint64_t *docids = NULL, *vals = NULL; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "saa", &index, &index_len, &attributes, &values) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - attrs_num = zend_hash_num_elements(Z_ARRVAL_P(attributes)); - - if (!attrs_num) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "empty attributes array passed"); - RETURN_FALSE; - } - - values_num = zend_hash_num_elements(Z_ARRVAL_P(values)); - - if (!values_num) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "empty values array passed"); - RETURN_FALSE; - } - - attrs = emalloc(sizeof(char *) * attrs_num); - for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(attributes)); - zend_hash_get_current_data(Z_ARRVAL_P(attributes), (void **) &item) != FAILURE; - zend_hash_move_forward(Z_ARRVAL_P(attributes))) { - if (Z_TYPE_PP(item) != IS_STRING) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "non-string attributes are not allowed"); - break; - } - attrs[a] = Z_STRVAL_PP(item); /* no copying here! */ - a++; - } - - /* cleanup on error */ - if (a != attrs_num) { - RETVAL_FALSE; - goto cleanup; - } - - docids = emalloc(sizeof(sphinx_uint64_t) * values_num); - vals = safe_emalloc(values_num * attrs_num, sizeof(sphinx_uint64_t), 0); - for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(values)); - zend_hash_get_current_data(Z_ARRVAL_P(values), (void **) &item) != FAILURE; - zend_hash_move_forward(Z_ARRVAL_P(values))) { - char *str_id; - ulong id; - zval **attr_value; - int failed = 0, key_type; - uint str_id_len; - double float_id = 0; - unsigned char id_type; - - if (Z_TYPE_PP(item) != IS_ARRAY) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "value is not an array of attributes"); - break; - } - - if (zend_hash_num_elements(Z_ARRVAL_PP(item)) != attrs_num) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "number of values is not equal to the number of attributes"); - break; - } - - key_type = zend_hash_get_current_key_ex(Z_ARRVAL_P(values), &str_id, &str_id_len, &id, 0, NULL); - - if (key_type == HASH_KEY_IS_LONG) { - /* ok */ - id_type = IS_LONG; - } else if (key_type == HASH_KEY_IS_STRING) { - id_type = is_numeric_string(str_id, str_id_len, (long *)&id, &float_id, 0); - if (id_type == IS_LONG || id_type == IS_DOUBLE) { - /* ok */ - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "document ID must be numeric"); - break; - } - } else { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "document ID must be integer"); - break; - } - - for (zend_hash_internal_pointer_reset(Z_ARRVAL_PP(item)); - zend_hash_get_current_data(Z_ARRVAL_PP(item), (void **) &attr_value) != FAILURE; - zend_hash_move_forward(Z_ARRVAL_PP(item))) { - if (Z_TYPE_PP(attr_value) != IS_LONG) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "attribute value must be integer"); - failed = 1; - break; - } - vals[j] = (sphinx_uint64_t)Z_LVAL_PP(attr_value); - j++; - } - - if (failed) { - break; - } - - if (id_type == IS_LONG) { - docids[i] = (sphinx_uint64_t)id; - } else { /* IS_FLOAT */ - docids[i] = (sphinx_uint64_t)float_id; - } - i++; - } - - if (i != values_num) { - RETVAL_FALSE; - goto cleanup; - } - - res = sphinx_update_attributes(c->sphinx, index, (int)attrs_num, attrs, values_num, docids, vals); - - if (res < 0) { - RETVAL_FALSE; - } else { - RETVAL_LONG(res); - } - -cleanup: - efree(attrs); - if (docids) { - efree(docids); - } - if (vals) { - efree(vals); - } -} -/* }}} */ - -/* {{{ proto array SphinxClient::buildExcerpts(array docs, string index, string words[, array opts]) */ -static PHP_METHOD(SphinxClient, buildExcerpts) -{ - php_sphinx_client *c; - zval *docs_array, *opts_array = NULL, **item; - char *index, *words; - const char **docs; - sphinx_excerpt_options opts; - int index_len, words_len; - int docs_num, i = 0; - char **result; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ass|a", &docs_array, &index, &index_len, &words, &words_len, &opts_array) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - docs_num = zend_hash_num_elements(Z_ARRVAL_P(docs_array)); - - if (!docs_num) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "empty documents array passed"); - RETURN_FALSE; - } - - docs = emalloc(sizeof(char *) * docs_num); - for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(docs_array)); - zend_hash_get_current_data(Z_ARRVAL_P(docs_array), (void **) &item) != FAILURE; - zend_hash_move_forward(Z_ARRVAL_P(docs_array))) { - if (Z_TYPE_PP(item) != IS_STRING) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "non-string documents are not allowed"); - break; - } - docs[i] = Z_STRVAL_PP(item); /* no copying here! */ - i++; - } - - if (i != docs_num) { - RETVAL_FALSE; - goto cleanup; - } - -#define OPTS_EQUAL(str, str_len, txt) str_len == sizeof(txt) && memcmp(txt, str, sizeof(txt)) == 0 - - if (opts_array) { - char *string_key; - unsigned int string_key_len; - ulong dummy; - - /* nullify everything */ - memset(&opts, 0, sizeof(sphinx_excerpt_options)); - for (zend_hash_internal_pointer_reset(Z_ARRVAL_P(opts_array)); - zend_hash_get_current_data(Z_ARRVAL_P(opts_array), (void **) &item) != FAILURE; - zend_hash_move_forward(Z_ARRVAL_P(opts_array))) { - - switch (Z_TYPE_PP(item)) { - case IS_STRING: - case IS_LONG: - case IS_BOOL: - break; - default: - continue; /* ignore invalid options */ - } - - if (zend_hash_get_current_key_ex(Z_ARRVAL_P(opts_array), &string_key, &string_key_len, &dummy, 0, NULL) != HASH_KEY_IS_STRING) { - continue; /* ignore invalid option names */ - } - - if (OPTS_EQUAL(string_key, string_key_len, "before_match")) { - SEPARATE_ZVAL(item); - convert_to_string_ex(item); - opts.before_match = Z_STRVAL_PP(item); - } else if (OPTS_EQUAL(string_key, string_key_len, "after_match")) { - SEPARATE_ZVAL(item); - convert_to_string_ex(item); - opts.after_match = Z_STRVAL_PP(item); - } else if (OPTS_EQUAL(string_key, string_key_len, "chunk_separator")) { - SEPARATE_ZVAL(item); - convert_to_string_ex(item); - opts.chunk_separator = Z_STRVAL_PP(item); - } else if (OPTS_EQUAL(string_key, string_key_len, "limit")) { - SEPARATE_ZVAL(item); - convert_to_long_ex(item); - opts.limit = (int)Z_LVAL_PP(item); - } else if (OPTS_EQUAL(string_key, string_key_len, "around")) { - SEPARATE_ZVAL(item); - convert_to_long_ex(item); - opts.around = (int)Z_LVAL_PP(item); - } else if (OPTS_EQUAL(string_key, string_key_len, "exact_phrase")) { - SEPARATE_ZVAL(item); - convert_to_boolean_ex(item); - opts.exact_phrase = Z_LVAL_PP(item); - } else if (OPTS_EQUAL(string_key, string_key_len, "single_passage")) { - SEPARATE_ZVAL(item); - convert_to_boolean_ex(item); - opts.single_passage = Z_LVAL_PP(item); - } else if (OPTS_EQUAL(string_key, string_key_len, "use_boundaries")) { - SEPARATE_ZVAL(item); - convert_to_boolean_ex(item); - opts.use_boundaries = Z_LVAL_PP(item); - } else if (OPTS_EQUAL(string_key, string_key_len, "weight_order")) { - SEPARATE_ZVAL(item); - convert_to_boolean_ex(item); - opts.weight_order = Z_LVAL_PP(item); - } else { - /* ignore invalid option names */ - } - } - } - - if (opts_array) { - result = sphinx_build_excerpts(c->sphinx, docs_num, docs, index, words, &opts); - } else { - result = sphinx_build_excerpts(c->sphinx, docs_num, docs, index, words, NULL); - } - - if (!result) { - RETVAL_FALSE; - } else { - array_init(return_value); - for (i = 0; i < docs_num; i++) { - if (result[i] && result[i][0] != '\0') { - add_next_index_string(return_value, result[i], 1); - } else { - add_next_index_string(return_value, "", 1); - } - free(result[i]); - } - free(result); - } - -cleanup: - efree(docs); -} -/* }}} */ - -/* {{{ proto array SphinxClient::buildKeywords(string query, string index, bool hits) */ -static PHP_METHOD(SphinxClient, buildKeywords) -{ - php_sphinx_client *c; - char *query, *index; - int query_len, index_len; - zend_bool hits; - sphinx_keyword_info *result; - int i, num_keywords; - zval *tmp; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ssb", &query, &query_len, &index, &index_len, &hits) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - result = sphinx_build_keywords(c->sphinx, query, index, hits, &num_keywords); - if (!result || num_keywords <= 0) { - RETURN_FALSE; - } - - array_init(return_value); - for (i = 0; i < num_keywords; i++) { - MAKE_STD_ZVAL(tmp); - array_init(tmp); - - add_assoc_string_ex(tmp, "tokenized", sizeof("tokenized"), result[i].tokenized, 1); - add_assoc_string_ex(tmp, "normalized", sizeof("normalized"), result[i].normalized, 1); - - if (hits) { - add_assoc_long_ex(tmp, "docs", sizeof("docs"), result[i].num_docs); - add_assoc_long_ex(tmp, "hits", sizeof("hits"), result[i].num_hits); - } - - add_next_index_zval(return_value, tmp); - - free(result[i].tokenized); - free(result[i].normalized); - } - free(result); -} -/* }}} */ - -/* {{{ proto void SphinxClient::resetFilters() */ -static PHP_METHOD(SphinxClient, resetFilters) -{ - php_sphinx_client *c; - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - sphinx_reset_filters(c->sphinx); -} -/* }}} */ - -/* {{{ proto void SphinxClient::resetGroupBy() */ -static PHP_METHOD(SphinxClient, resetGroupBy) -{ - php_sphinx_client *c; - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - sphinx_reset_groupby(c->sphinx); -} -/* }}} */ - -/* {{{ proto string SphinxClient::getLastWarning() */ -static PHP_METHOD(SphinxClient, getLastWarning) -{ - php_sphinx_client *c; - const char *warning; - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - warning = sphinx_warning(c->sphinx); - if (!warning || !warning[0]) { - RETURN_EMPTY_STRING(); - } - RETURN_STRING((char *)warning, 1); -} -/* }}} */ - -/* {{{ proto string SphinxClient::getLastError() */ -static PHP_METHOD(SphinxClient, getLastError) -{ - php_sphinx_client *c; - const char *error; - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - error = sphinx_error(c->sphinx); - if (!error || !error[0]) { - RETURN_EMPTY_STRING(); - } - RETURN_STRING((char *)error, 1); -} -/* }}} */ - -/* {{{ proto array SphinxClient::query(string query[, string index[, string comment]]) */ -static PHP_METHOD(SphinxClient, query) -{ - php_sphinx_client *c; - char *query, *index = "*", *comment = ""; - int query_len, index_len, comment_len; - sphinx_result *result; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ss", &query, &query_len, &index, &index_len, &comment, &comment_len) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - result = sphinx_query(c->sphinx, query, index, comment); - - if (!result) { - RETURN_FALSE; - } - - php_sphinx_result_to_array(c, result, &return_value TSRMLS_CC); -} - -/* }}} */ - -/* {{{ proto int SphinxClient::addQuery(string query[, string index[, string comment]]) */ -static PHP_METHOD(SphinxClient, addQuery) -{ - php_sphinx_client *c; - char *query, *index = "*", *comment = ""; - int query_len, index_len, comment_len, res; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ss", &query, &query_len, &index, &index_len, &comment, &comment_len) == FAILURE) { - return; - } - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - res = sphinx_add_query(c->sphinx, query, index, comment); - - if (res < 0) { - RETURN_FALSE; - } - RETURN_LONG(res); -} - -/* }}} */ - -/* {{{ proto array SphinxClient::runQueries() */ -static PHP_METHOD(SphinxClient, runQueries) -{ - php_sphinx_client *c; - sphinx_result *results; - int i, num_results; - zval *single_result; - - c = (php_sphinx_client *)zend_object_store_get_object(getThis() TSRMLS_CC); - - results = sphinx_run_queries(c->sphinx); - - if (!results) { - RETURN_FALSE; - } - - num_results = sphinx_get_num_results(c->sphinx); - - array_init(return_value); - for (i = 0; i < num_results; i++) { - MAKE_STD_ZVAL(single_result); - php_sphinx_result_to_array(c, &results[i], &single_result TSRMLS_CC); - add_next_index_zval(return_value, single_result); - } -} -/* }}} */ - -/* {{{ proto string SphinxClient::escapeString(string data) */ -static PHP_METHOD(SphinxClient, escapeString) -{ - char *str, *new_str, *source, *target; - int str_len, new_str_len, i; - - if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &str, &str_len) == FAILURE) { - return; - } - - if (!str_len) { - RETURN_EMPTY_STRING(); - } - - new_str = safe_emalloc(2, str_len, 1); - target = new_str; - source = str; - for (i = 0; i < str_len; i++) { - switch (*source) { - case '(': - case ')': - case '|': - case '-': - case '!': - case '@': - case '~': - case '"': - case '&': - case '/': - case '\\': - *target++ = '\\'; - *target++ = *source; - break; - default: - *target++ = *source; - break; - } - source++; - } - *target = '\0'; - - new_str_len = target - new_str; - new_str = erealloc(new_str, new_str_len + 1); - RETURN_STRINGL(new_str, new_str_len, 0); -} -/* }}} */ - -/* {{{ proto int SphinxClient::__sleep() */ -static PHP_METHOD(SphinxClient, __sleep) -{ - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "SphinxClient instance cannot be (un)serialized"); -} -/* }}} */ - -/* {{{ proto int SphinxClient::__wakeup() */ -static PHP_METHOD(SphinxClient, __wakeup) -{ - php_error_docref(NULL TSRMLS_CC, E_RECOVERABLE_ERROR, "SphinxClient instance cannot be (un)serialized"); -} -/* }}} */ - -/* {{{ arginfo */ -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setserver, 0, 0, 2) - ZEND_ARG_INFO(0, server) - ZEND_ARG_INFO(0, port) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setlimits, 0, 0, 2) - ZEND_ARG_INFO(0, offset) - ZEND_ARG_INFO(0, limit) - ZEND_ARG_INFO(0, max_matches) - ZEND_ARG_INFO(0, cutoff) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setmatchmode, 0, 0, 1) - ZEND_ARG_INFO(0, mode) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setindexweights, 0, 0, 1) - ZEND_ARG_INFO(0, weights) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setidrange, 0, 0, 2) - ZEND_ARG_INFO(0, min) - ZEND_ARG_INFO(0, max) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setfilter, 0, 0, 2) - ZEND_ARG_INFO(0, attribute) - ZEND_ARG_INFO(0, values) - ZEND_ARG_INFO(0, exclude) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setfilterrange, 0, 0, 3) - ZEND_ARG_INFO(0, attribute) - ZEND_ARG_INFO(0, min) - ZEND_ARG_INFO(0, max) - ZEND_ARG_INFO(0, exclude) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setgeoanchor, 0, 0, 4) - ZEND_ARG_INFO(0, attrlat) - ZEND_ARG_INFO(0, attrlong) - ZEND_ARG_INFO(0, latitude) - ZEND_ARG_INFO(0, longitude) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setgroupby, 0, 0, 2) - ZEND_ARG_INFO(0, attribute) - ZEND_ARG_INFO(0, func) - ZEND_ARG_INFO(0, groupsort) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setgroupdistinct, 0, 0, 1) - ZEND_ARG_INFO(0, attribute) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setretries, 0, 0, 1) - ZEND_ARG_INFO(0, count) - ZEND_ARG_INFO(0, delay) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setmaxquerytime, 0, 0, 1) - ZEND_ARG_INFO(0, qtime) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setrankingmode, 0, 0, 1) - ZEND_ARG_INFO(0, ranker) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setsortmode, 0, 0, 1) - ZEND_ARG_INFO(0, mode) - ZEND_ARG_INFO(0, sortby) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setconnecttimeout, 0, 0, 1) - ZEND_ARG_INFO(0, timeout) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setarrayresult, 0, 0, 1) - ZEND_ARG_INFO(0, array_result) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_updateattributes, 0, 0, 3) - ZEND_ARG_INFO(0, index) - ZEND_ARG_INFO(0, attributes) - ZEND_ARG_INFO(0, values) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_buildexcerpts, 0, 0, 3) - ZEND_ARG_INFO(0, docs) - ZEND_ARG_INFO(0, index) - ZEND_ARG_INFO(0, words) - ZEND_ARG_INFO(0, opts) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_buildkeywords, 0, 0, 3) - ZEND_ARG_INFO(0, query) - ZEND_ARG_INFO(0, index) - ZEND_ARG_INFO(0, hits) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_query, 0, 0, 1) - ZEND_ARG_INFO(0, query) - ZEND_ARG_INFO(0, index) - ZEND_ARG_INFO(0, comment) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO(arginfo_sphinxclient__param_void, 0) -ZEND_END_ARG_INFO() - -ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_escapestring, 0, 0, 1) - ZEND_ARG_INFO(0, data) -ZEND_END_ARG_INFO() -/* }}} */ - -static zend_function_entry sphinx_client_methods[] = { /* {{{ */ - PHP_ME(SphinxClient, __construct, arginfo_sphinxclient__param_void, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, addQuery, arginfo_sphinxclient_query, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, buildExcerpts, arginfo_sphinxclient_buildexcerpts, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, buildKeywords, arginfo_sphinxclient_buildkeywords, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, getLastError, arginfo_sphinxclient__param_void, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, getLastWarning, arginfo_sphinxclient__param_void, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, escapeString, arginfo_sphinxclient_escapestring, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, query, arginfo_sphinxclient_query, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, resetFilters, arginfo_sphinxclient__param_void, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, resetGroupBy, arginfo_sphinxclient__param_void, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, runQueries, arginfo_sphinxclient__param_void, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, setArrayResult, arginfo_sphinxclient_setarrayresult, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, setConnectTimeout, arginfo_sphinxclient_setconnecttimeout, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, setFieldWeights, arginfo_sphinxclient_setindexweights, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, setFilter, arginfo_sphinxclient_setfilter, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, setFilterFloatRange, arginfo_sphinxclient_setfilterrange, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, setFilterRange, arginfo_sphinxclient_setfilterrange, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, setGeoAnchor, arginfo_sphinxclient_setgeoanchor, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, setGroupBy, arginfo_sphinxclient_setgroupby, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, setGroupDistinct, arginfo_sphinxclient_setgroupdistinct, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, setIndexWeights, arginfo_sphinxclient_setindexweights, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, setIDRange, arginfo_sphinxclient_setidrange, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, setLimits, arginfo_sphinxclient_setlimits, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, setMatchMode, arginfo_sphinxclient_setmatchmode, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, setMaxQueryTime, arginfo_sphinxclient_setmaxquerytime, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, setRankingMode, arginfo_sphinxclient_setrankingmode, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, setRetries, arginfo_sphinxclient_setretries, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, setServer, arginfo_sphinxclient_setserver, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, setSortMode, arginfo_sphinxclient_setsortmode, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, updateAttributes, arginfo_sphinxclient_updateattributes, ZEND_ACC_PUBLIC) - PHP_ME(SphinxClient, __sleep, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) - PHP_ME(SphinxClient, __wakeup, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) - {NULL, NULL, NULL} -}; -/* }}} */ - -/* {{{ PHP_MINIT_FUNCTION - */ -PHP_MINIT_FUNCTION(sphinx) -{ - zend_class_entry ce; - - memcpy(&cannot_be_cloned, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); - cannot_be_cloned.clone_obj = NULL; - - memcpy(&php_sphinx_client_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); - php_sphinx_client_handlers.clone_obj = NULL; - php_sphinx_client_handlers.read_property = php_sphinx_client_read_property; - php_sphinx_client_handlers.get_properties = php_sphinx_client_get_properties; - - INIT_CLASS_ENTRY(ce, "SphinxClient", sphinx_client_methods); - ce_sphinx_client = zend_register_internal_class(&ce TSRMLS_CC); - ce_sphinx_client->create_object = php_sphinx_client_new; - - SPHINX_CONST(SEARCHD_OK); - SPHINX_CONST(SEARCHD_ERROR); - SPHINX_CONST(SEARCHD_RETRY); - SPHINX_CONST(SEARCHD_WARNING); - - SPHINX_CONST(SPH_MATCH_ALL); - SPHINX_CONST(SPH_MATCH_ANY); - SPHINX_CONST(SPH_MATCH_PHRASE); - SPHINX_CONST(SPH_MATCH_BOOLEAN); - SPHINX_CONST(SPH_MATCH_EXTENDED); - SPHINX_CONST(SPH_MATCH_FULLSCAN); - SPHINX_CONST(SPH_MATCH_EXTENDED2); - - SPHINX_CONST(SPH_RANK_PROXIMITY_BM25); - SPHINX_CONST(SPH_RANK_BM25); - SPHINX_CONST(SPH_RANK_NONE); - SPHINX_CONST(SPH_RANK_WORDCOUNT); - - SPHINX_CONST(SPH_SORT_RELEVANCE); - SPHINX_CONST(SPH_SORT_ATTR_DESC); - SPHINX_CONST(SPH_SORT_ATTR_ASC); - SPHINX_CONST(SPH_SORT_TIME_SEGMENTS); - SPHINX_CONST(SPH_SORT_EXTENDED); - SPHINX_CONST(SPH_SORT_EXPR); - - SPHINX_CONST(SPH_FILTER_VALUES); - SPHINX_CONST(SPH_FILTER_RANGE); - SPHINX_CONST(SPH_FILTER_FLOATRANGE); - - SPHINX_CONST(SPH_ATTR_INTEGER); - SPHINX_CONST(SPH_ATTR_TIMESTAMP); - SPHINX_CONST(SPH_ATTR_ORDINAL); - SPHINX_CONST(SPH_ATTR_BOOL); - SPHINX_CONST(SPH_ATTR_FLOAT); - SPHINX_CONST(SPH_ATTR_MULTI); - - SPHINX_CONST(SPH_GROUPBY_DAY); - SPHINX_CONST(SPH_GROUPBY_WEEK); - SPHINX_CONST(SPH_GROUPBY_MONTH); - SPHINX_CONST(SPH_GROUPBY_YEAR); - SPHINX_CONST(SPH_GROUPBY_ATTR); - SPHINX_CONST(SPH_GROUPBY_ATTRPAIR); - - return SUCCESS; -} -/* }}} */ - -/* {{{ PHP_MINFO_FUNCTION - */ -PHP_MINFO_FUNCTION(sphinx) -{ - php_info_print_table_start(); - php_info_print_table_header(2, "sphinx support", "enabled"); - php_info_print_table_header(2, "Version", PHP_SPHINX_VERSION); - php_info_print_table_header(2, "Revision", "$Revision: 1.17 $"); - php_info_print_table_end(); -} -/* }}} */ - -static zend_function_entry sphinx_functions[] = { /* {{{ */ - {NULL, NULL, NULL} -}; -/* }}} */ - -/* {{{ sphinx_module_entry - */ -zend_module_entry sphinx_module_entry = { -#if ZEND_MODULE_API_NO >= 20010901 - STANDARD_MODULE_HEADER, -#endif - "sphinx", - sphinx_functions, - PHP_MINIT(sphinx), - NULL, - NULL, - NULL, - PHP_MINFO(sphinx), -#if ZEND_MODULE_API_NO >= 20010901 - PHP_SPHINX_VERSION, -#endif - STANDARD_MODULE_PROPERTIES -}; -/* }}} */ - -/* - * Local variables: - * tab-width: 4 - * c-basic-offset: 4 - * End: - * vim600: noet sw=4 ts=4 fdm=marker - * vim<600: noet sw=4 ts=4 - */ | ||
Deleted | sphinx-1.0.2.tgz ^ | |
Deleted | sphinx-1.0.3.tgz ^ | |
Deleted | sphinx-1.2.0.tgz ^ | |
Deleted | sphinx-1.3.0.tgz ^ | |
Deleted | sphinx-1.3.2.tgz ^ | |
[+] | Added | sphinx-1.3.99.1.tgz/.git ^ |
+(directory) | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/HEAD ^ |
@@ -0,0 +1 @@ +ref: refs/heads/php7 | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/branches ^ |
+(directory) | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/config ^ |
@@ -0,0 +1,11 @@ +[core] + repositoryformatversion = 0 + filemode = true + bare = false + logallrefupdates = true +[remote "origin"] + url = https://git.php.net/repository/pecl/search_engine/sphinx.git + fetch = +refs/heads/*:refs/remotes/origin/* +[branch "php7"] + remote = origin + merge = refs/heads/php7 | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/description ^ |
@@ -0,0 +1 @@ +Unnamed repository; edit this file 'description' to name the repository. | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/hooks ^ |
+(directory) | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/hooks/applypatch-msg.sample ^ |
@@ -0,0 +1,15 @@ +#!/bin/sh +# +# An example hook script to check the commit log message taken by +# applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. The hook is +# allowed to edit the commit message file. +# +# To enable this hook, rename this file to "applypatch-msg". + +. git-sh-setup +test -x "$GIT_DIR/hooks/commit-msg" && + exec "$GIT_DIR/hooks/commit-msg" ${1+"$@"} +: | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/hooks/commit-msg.sample ^ |
@@ -0,0 +1,24 @@ +#!/bin/sh +# +# An example hook script to check the commit log message. +# Called by "git commit" with one argument, the name of the file +# that has the commit message. The hook should exit with non-zero +# status after issuing an appropriate message if it wants to stop the +# commit. The hook is allowed to edit the commit message file. +# +# To enable this hook, rename this file to "commit-msg". + +# Uncomment the below to add a Signed-off-by line to the message. +# Doing this in a hook is a bad idea in general, but the prepare-commit-msg +# hook is more suited to it. +# +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" + +# This example catches duplicate Signed-off-by lines. + +test "" = "$(grep '^Signed-off-by: ' "$1" | + sort | uniq -c | sed -e '/^[ ]*1[ ]/d')" || { + echo >&2 Duplicate Signed-off-by lines. + exit 1 +} | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/hooks/post-update.sample ^ |
@@ -0,0 +1,8 @@ +#!/bin/sh +# +# An example hook script to prepare a packed repository for use over +# dumb transports. +# +# To enable this hook, rename this file to "post-update". + +exec git update-server-info | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/hooks/pre-applypatch.sample ^ |
@@ -0,0 +1,14 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed +# by applypatch from an e-mail message. +# +# The hook should exit with non-zero status after issuing an +# appropriate message if it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-applypatch". + +. git-sh-setup +test -x "$GIT_DIR/hooks/pre-commit" && + exec "$GIT_DIR/hooks/pre-commit" ${1+"$@"} +: | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/hooks/pre-commit.sample ^ |
@@ -0,0 +1,50 @@ +#!/bin/sh +# +# An example hook script to verify what is about to be committed. +# Called by "git commit" with no arguments. The hook should +# exit with non-zero status after issuing an appropriate message if +# it wants to stop the commit. +# +# To enable this hook, rename this file to "pre-commit". + +if git rev-parse --verify HEAD >/dev/null 2>&1 +then + against=HEAD +else + # Initial commit: diff against an empty tree object + against=4b825dc642cb6eb9a060e54bf8d69288fbee4904 +fi + +# If you want to allow non-ascii filenames set this variable to true. +allownonascii=$(git config hooks.allownonascii) + +# Redirect output to stderr. +exec 1>&2 + +# Cross platform projects tend to avoid non-ascii filenames; prevent +# them from being added to the repository. We exploit the fact that the +# printable range starts at the space character and ends with tilde. +if [ "$allownonascii" != "true" ] && + # Note that the use of brackets around a tr range is ok here, (it's + # even required, for portability to Solaris 10's /usr/bin/tr), since + # the square bracket bytes happen to fall in the designated range. + test $(git diff --cached --name-only --diff-filter=A -z $against | + LC_ALL=C tr -d '[ -~]\0' | wc -c) != 0 +then + echo "Error: Attempt to add a non-ascii file name." + echo + echo "This can cause problems if you want to work" + echo "with people on other platforms." + echo + echo "To be portable it is advisable to rename the file ..." + echo + echo "If you know what you are doing you can disable this" + echo "check using:" + echo + echo " git config hooks.allownonascii true" + echo + exit 1 +fi + +# If there are whitespace errors, print the offending file names and fail. +exec git diff-index --check --cached $against -- | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/hooks/pre-rebase.sample ^ |
@@ -0,0 +1,169 @@ +#!/bin/sh +# +# Copyright (c) 2006, 2008 Junio C Hamano +# +# The "pre-rebase" hook is run just before "git rebase" starts doing +# its job, and can prevent the command from running by exiting with +# non-zero status. +# +# The hook is called with the following parameters: +# +# $1 -- the upstream the series was forked from. +# $2 -- the branch being rebased (or empty when rebasing the current branch). +# +# This sample shows how to prevent topic branches that are already +# merged to 'next' branch from getting rebased, because allowing it +# would result in rebasing already published history. + +publish=next +basebranch="$1" +if test "$#" = 2 +then + topic="refs/heads/$2" +else + topic=`git symbolic-ref HEAD` || + exit 0 ;# we do not interrupt rebasing detached HEAD +fi + +case "$topic" in +refs/heads/??/*) + ;; +*) + exit 0 ;# we do not interrupt others. + ;; +esac + +# Now we are dealing with a topic branch being rebased +# on top of master. Is it OK to rebase it? + +# Does the topic really exist? +git show-ref -q "$topic" || { + echo >&2 "No such branch $topic" + exit 1 +} + +# Is topic fully merged to master? +not_in_master=`git rev-list --pretty=oneline ^master "$topic"` +if test -z "$not_in_master" +then + echo >&2 "$topic is fully merged to master; better remove it." + exit 1 ;# we could allow it, but there is no point. +fi + +# Is topic ever merged to next? If so you should not be rebasing it. +only_next_1=`git rev-list ^master "^$topic" ${publish} | sort` +only_next_2=`git rev-list ^master ${publish} | sort` +if test "$only_next_1" = "$only_next_2" +then + not_in_topic=`git rev-list "^$topic" master` + if test -z "$not_in_topic" + then + echo >&2 "$topic is already up-to-date with master" + exit 1 ;# we could allow it, but there is no point. + else + exit 0 + fi +else + not_in_next=`git rev-list --pretty=oneline ^${publish} "$topic"` + /usr/bin/perl -e ' + my $topic = $ARGV[0]; + my $msg = "* $topic has commits already merged to public branch:\n"; + my (%not_in_next) = map { + /^([0-9a-f]+) /; + ($1 => 1); + } split(/\n/, $ARGV[1]); + for my $elem (map { + /^([0-9a-f]+) (.*)$/; + [$1 => $2]; + } split(/\n/, $ARGV[2])) { + if (!exists $not_in_next{$elem->[0]}) { + if ($msg) { + print STDERR $msg; + undef $msg; + } + print STDERR " $elem->[1]\n"; + } + } + ' "$topic" "$not_in_next" "$not_in_master" + exit 1 +fi + +exit 0 + +################################################################ + +This sample hook safeguards topic branches that have been +published from being rewound. + +The workflow assumed here is: + + * Once a topic branch forks from "master", "master" is never + merged into it again (either directly or indirectly). + + * Once a topic branch is fully cooked and merged into "master", + it is deleted. If you need to build on top of it to correct + earlier mistakes, a new topic branch is created by forking at + the tip of the "master". This is not strictly necessary, but + it makes it easier to keep your history simple. + + * Whenever you need to test or publish your changes to topic + branches, merge them into "next" branch. + +The script, being an example, hardcodes the publish branch name +to be "next", but it is trivial to make it configurable via +$GIT_DIR/config mechanism. + +With this workflow, you would want to know: + +(1) ... if a topic branch has ever been merged to "next". Young + topic branches can have stupid mistakes you would rather + clean up before publishing, and things that have not been + merged into other branches can be easily rebased without + affecting other people. But once it is published, you would + not want to rewind it. + +(2) ... if a topic branch has been fully merged to "master". + Then you can delete it. More importantly, you should not + build on top of it -- other people may already want to + change things related to the topic as patches against your + "master", so if you need further changes, it is better to + fork the topic (perhaps with the same name) afresh from the + tip of "master". + +Let's look at this example: + + o---o---o---o---o---o---o---o---o---o "next" + / / / / + / a---a---b A / / + / / / / + / / c---c---c---c B / + / / / \ / + / / / b---b C \ / + / / / / \ / + ---o---o---o---o---o---o---o---o---o---o---o "master" + + +A, B and C are topic branches. + + * A has one fix since it was merged up to "next". + + * B has finished. It has been fully merged up to "master" and "next", + and is ready to be deleted. + + * C has not merged to "next" at all. + +We would want to allow C to be rebased, refuse A, and encourage +B to be deleted. + +To compute (1): + + git rev-list ^master ^topic next + git rev-list ^master next + + if these match, topic has not merged in next at all. + +To compute (2): + + git rev-list master..topic + + if this is empty, it is fully merged to "master". | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/hooks/prepare-commit-msg.sample ^ |
@@ -0,0 +1,36 @@ +#!/bin/sh +# +# An example hook script to prepare the commit log message. +# Called by "git commit" with the name of the file that has the +# commit message, followed by the description of the commit +# message's source. The hook's purpose is to edit the commit +# message file. If the hook fails with a non-zero status, +# the commit is aborted. +# +# To enable this hook, rename this file to "prepare-commit-msg". + +# This hook includes three examples. The first comments out the +# "Conflicts:" part of a merge commit. +# +# The second includes the output of "git diff --name-status -r" +# into the message, just before the "git status" output. It is +# commented because it doesn't cope with --amend or with squashed +# commits. +# +# The third example adds a Signed-off-by line to the message, that can +# still be edited. This is rarely a good idea. + +case "$2,$3" in + merge,) + /usr/bin/perl -i.bak -ne 's/^/# /, s/^# #/#/ if /^Conflicts/ .. /#/; print' "$1" ;; + +# ,|template,) +# /usr/bin/perl -i.bak -pe ' +# print "\n" . `git diff --cached --name-status -r` +# if /^#/ && $first++ == 0' "$1" ;; + + *) ;; +esac + +# SOB=$(git var GIT_AUTHOR_IDENT | sed -n 's/^\(.*>\).*$/Signed-off-by: \1/p') +# grep -qs "^$SOB" "$1" || echo "$SOB" >> "$1" | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/hooks/update.sample ^ |
@@ -0,0 +1,128 @@ +#!/bin/sh +# +# An example hook script to blocks unannotated tags from entering. +# Called by "git receive-pack" with arguments: refname sha1-old sha1-new +# +# To enable this hook, rename this file to "update". +# +# Config +# ------ +# hooks.allowunannotated +# This boolean sets whether unannotated tags will be allowed into the +# repository. By default they won't be. +# hooks.allowdeletetag +# This boolean sets whether deleting tags will be allowed in the +# repository. By default they won't be. +# hooks.allowmodifytag +# This boolean sets whether a tag may be modified after creation. By default +# it won't be. +# hooks.allowdeletebranch +# This boolean sets whether deleting branches will be allowed in the +# repository. By default they won't be. +# hooks.denycreatebranch +# This boolean sets whether remotely creating branches will be denied +# in the repository. By default this is allowed. +# + +# --- Command line +refname="$1" +oldrev="$2" +newrev="$3" + +# --- Safety check +if [ -z "$GIT_DIR" ]; then + echo "Don't run this script from the command line." >&2 + echo " (if you want, you could supply GIT_DIR then run" >&2 + echo " $0 <ref> <oldrev> <newrev>)" >&2 + exit 1 +fi + +if [ -z "$refname" -o -z "$oldrev" -o -z "$newrev" ]; then + echo "Usage: $0 <ref> <oldrev> <newrev>" >&2 + exit 1 +fi + +# --- Config +allowunannotated=$(git config --bool hooks.allowunannotated) +allowdeletebranch=$(git config --bool hooks.allowdeletebranch) +denycreatebranch=$(git config --bool hooks.denycreatebranch) +allowdeletetag=$(git config --bool hooks.allowdeletetag) +allowmodifytag=$(git config --bool hooks.allowmodifytag) + +# check for no description +projectdesc=$(sed -e '1q' "$GIT_DIR/description") +case "$projectdesc" in +"Unnamed repository"* | "") + echo "*** Project description file hasn't been set" >&2 + exit 1 + ;; +esac + +# --- Check types +# if $newrev is 0000...0000, it's a commit to delete a ref. +zero="0000000000000000000000000000000000000000" +if [ "$newrev" = "$zero" ]; then + newrev_type=delete +else + newrev_type=$(git cat-file -t $newrev) +fi + +case "$refname","$newrev_type" in + refs/tags/*,commit) + # un-annotated tag + short_refname=${refname##refs/tags/} + if [ "$allowunannotated" != "true" ]; then + echo "*** The un-annotated tag, $short_refname, is not allowed in this repository" >&2 + echo "*** Use 'git tag [ -a | -s ]' for tags you want to propagate." >&2 + exit 1 + fi + ;; + refs/tags/*,delete) + # delete tag + if [ "$allowdeletetag" != "true" ]; then + echo "*** Deleting a tag is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/tags/*,tag) + # annotated tag + if [ "$allowmodifytag" != "true" ] && git rev-parse $refname > /dev/null 2>&1 + then + echo "*** Tag '$refname' already exists." >&2 + echo "*** Modifying a tag is not allowed in this repository." >&2 + exit 1 + fi + ;; + refs/heads/*,commit) + # branch + if [ "$oldrev" = "$zero" -a "$denycreatebranch" = "true" ]; then + echo "*** Creating a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/heads/*,delete) + # delete branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + refs/remotes/*,commit) + # tracking branch + ;; + refs/remotes/*,delete) + # delete tracking branch + if [ "$allowdeletebranch" != "true" ]; then + echo "*** Deleting a tracking branch is not allowed in this repository" >&2 + exit 1 + fi + ;; + *) + # Anything else (is there anything else?) + echo "*** Update hook: unknown type of update to ref $refname of type $newrev_type" >&2 + exit 1 + ;; +esac + +# --- Finished +exit 0 | ||
Added | sphinx-1.3.99.1.tgz/.git/index ^ | |
[+] | Added | sphinx-1.3.99.1.tgz/.git/info ^ |
+(directory) | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/info/exclude ^ |
@@ -0,0 +1,6 @@ +# git ls-files --others --exclude-from=.git/info/exclude +# Lines that start with '#' are comments. +# For a project mostly in C, the following would be a good set of +# exclude patterns (uncomment them if you want to use them): +# *.[oa] +# *~ | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/logs ^ |
+(directory) | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/logs/HEAD ^ |
@@ -0,0 +1 @@ +0000000000000000000000000000000000000000 9a3d08c67af0cad216aa0d38d39be71362667738 Local OBS User <obs@mgmt-desk.obs.j0ke.net> 1461308568 +0200 clone: from https://git.php.net/repository/pecl/search_engine/sphinx.git | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/logs/refs ^ |
+(directory) | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/logs/refs/heads ^ |
+(directory) | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/logs/refs/heads/php7 ^ |
@@ -0,0 +1 @@ +0000000000000000000000000000000000000000 9a3d08c67af0cad216aa0d38d39be71362667738 Local OBS User <obs@mgmt-desk.obs.j0ke.net> 1461308568 +0200 clone: from https://git.php.net/repository/pecl/search_engine/sphinx.git | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/logs/refs/remotes ^ |
+(directory) | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/logs/refs/remotes/origin ^ |
+(directory) | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/logs/refs/remotes/origin/HEAD ^ |
@@ -0,0 +1 @@ +0000000000000000000000000000000000000000 7d9b13f64621bb0011743110b77e9f30c2f43b9b Local OBS User <obs@mgmt-desk.obs.j0ke.net> 1461308568 +0200 clone: from https://git.php.net/repository/pecl/search_engine/sphinx.git | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/objects ^ |
+(directory) | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/objects/info ^ |
+(directory) | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/objects/pack ^ |
+(directory) | ||
Added | sphinx-1.3.99.1.tgz/.git/objects/pack/pack-156141e462ea5d54d3ae9435f8efc82ad0ee5570.idx ^ | |
Added | sphinx-1.3.99.1.tgz/.git/objects/pack/pack-156141e462ea5d54d3ae9435f8efc82ad0ee5570.pack ^ | |
[+] | Added | sphinx-1.3.99.1.tgz/.git/packed-refs ^ |
@@ -0,0 +1,16 @@ +# pack-refs with: peeled +7d9b13f64621bb0011743110b77e9f30c2f43b9b refs/remotes/origin/master +9a3d08c67af0cad216aa0d38d39be71362667738 refs/remotes/origin/php7 +0a3df8dd793d4599487ffce2f3dc971e7ed8d917 refs/tags/RELEASE_0_1_0 +^3edc0ae37e1783da7ce766bf8341fad7ed92403b +ef82e70ebab56ae8eaba1a943c4fa579458620df refs/tags/RELEASE_0_2_0 +^44dfdc1355ea1a3720f76e18e5c5215eb4e85e0f +d215590113e406e07d432dc46ada12373fd852e3 refs/tags/RELEASE_1_0_0 +^34911f745b8e8f9bafb73e2f98f0d6315dfd09f0 +4cf83a9f4013306e7944a715460f1f1b038c04e7 refs/tags/RELEASE_1_0_3 +^320e62c30e405809e008cf3cb71e49dfc615f61e +e044cf207038c972f7e0b7defc80d0a2eb96e379 refs/tags/RELEASE_1_0_4 +^190d6d1e5ab2a6ffc3b0414fd72b31b4e5bfa7ac +54b3c387cbd24cb2ccb12a13fe4a2f70d72fff84 refs/tags/RELEASE_1_1_0 +^f24bbed1aff0d1bd6754c8b7eb9ed2b85ac79ca6 +2f40d68941ef245e0ee918e1a968be796128a666 refs/tags/RELEASE_1_3_3 | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/refs ^ |
+(directory) | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/refs/heads ^ |
+(directory) | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/refs/heads/php7 ^ |
@@ -0,0 +1 @@ +9a3d08c67af0cad216aa0d38d39be71362667738 | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/refs/remotes ^ |
+(directory) | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/refs/remotes/origin ^ |
+(directory) | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/refs/remotes/origin/HEAD ^ |
@@ -0,0 +1 @@ +ref: refs/remotes/origin/master | ||
[+] | Added | sphinx-1.3.99.1.tgz/.git/refs/tags ^ |
+(directory) | ||
[+] | Added | sphinx-1.3.99.1.tgz/CREDITS ^ |
@@ -0,0 +1,3 @@ +Sphinx client extension for PHP +Antony Dovgal (tony2001) +Alexey Romanenko (santiago) | ||
[+] | Added | sphinx-1.3.99.1.tgz/LICENSE ^ |
@@ -0,0 +1,68 @@ +-------------------------------------------------------------------- + The PHP License, version 3.01 +Copyright (c) 1999 - 2010 The PHP Group. All rights reserved. +-------------------------------------------------------------------- + +Redistribution and use in source and binary forms, with or without +modification, is permitted provided that the following conditions +are met: + + 1. Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + + 2. Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in + the documentation and/or other materials provided with the + distribution. + + 3. The name "PHP" must not be used to endorse or promote products + derived from this software without prior written permission. For + written permission, please contact group@php.net. + + 4. Products derived from this software may not be called "PHP", nor + may "PHP" appear in their name, without prior written permission + from group@php.net. You may indicate that your software works in + conjunction with PHP by saying "Foo for PHP" instead of calling + it "PHP Foo" or "phpfoo" + + 5. The PHP Group may publish revised and/or new versions of the + license from time to time. Each version will be given a + distinguishing version number. + Once covered code has been published under a particular version + of the license, you may always continue to use it under the terms + of that version. You may also choose to use such covered code + under the terms of any subsequent version of the license + published by the PHP Group. No one other than the PHP Group has + the right to modify the terms applicable to covered code created + under this License. + + 6. Redistributions of any form whatsoever must retain the following + acknowledgment: + "This product includes PHP software, freely available from + <http://www.php.net/software/>". + +THIS SOFTWARE IS PROVIDED BY THE PHP DEVELOPMENT TEAM ``AS IS'' AND +ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A +PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE PHP +DEVELOPMENT TEAM OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, +INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) +HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, +STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED +OF THE POSSIBILITY OF SUCH DAMAGE. + +-------------------------------------------------------------------- + +This software consists of voluntary contributions made by many +individuals on behalf of the PHP Group. + +The PHP Group can be contacted via Email at group@php.net. + +For more information on the PHP Group and the PHP project, +please see <http://www.php.net>. + +PHP includes the Zend Engine, freely available at +<http://www.zend.com>. | ||
[+] | Added | sphinx-1.3.99.1.tgz/config.m4 ^ |
@@ -0,0 +1,114 @@ +dnl $Id$ + +AC_DEFUN([SPHINX_CHECK_ENUM], [ + AC_MSG_CHECKING([for $1 in sphinxclient.h]) + AC_TRY_COMPILE([#include <sphinxclient.h>], [int i = $1], + [ + AC_DEFINE([HAVE_]$1, [], [Define if $1 is available]) + AC_MSG_RESULT([found]) + ], [ + AC_MSG_RESULT([not found]) + ]) +]) + +PHP_ARG_WITH(sphinx, for sphinx support, +[ --with-sphinx Include sphinx support]) + +if test "$PHP_SPHINX" != "no"; then + + SEARCH_PATH="/usr/local /usr /local /opt" + SEARCH_FOR="/include/sphinxclient.h" + + if test "$PHP_SPHINX" = "yes"; then + AC_MSG_CHECKING([for libsphinxclient headers in default path]) + for i in $SEARCH_PATH ; do + if test -r $i/$SEARCH_FOR; then + SPHINX_DIR=$i + AC_MSG_RESULT(found in $i) + fi + done + else + AC_MSG_CHECKING([for libsphinxclient headers in $PHP_SPHINX]) + if test -r $PHP_SPHINX/$SEARCH_FOR; then + SPHINX_DIR=$PHP_SPHINX + AC_MSG_RESULT([found]) + fi + fi + + if test -z "$SPHINX_DIR"; then + AC_MSG_RESULT([not found]) + AC_MSG_ERROR([Cannot find libsphinxclient headers]) + fi + + PHP_ADD_INCLUDE($SPHINX_DIR/include) + + LIBNAME=sphinxclient + LIBSYMBOL=sphinx_create + + PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL, + [ + PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $SPHINX_DIR/$PHP_LIBDIR, SPHINX_SHARED_LIBADD) + AC_DEFINE(HAVE_SPHINXLIB,1,[ ]) + ],[ + AC_MSG_ERROR([wrong libsphinxclient version or lib not found]) + ],[ + -L$SPHINX_DIR/$PHP_LIBDIR -lm + ]) + + PHP_CHECK_LIBRARY($LIBNAME,sphinx_get_string, + [ + PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $SPHINX_DIR/$PHP_LIBDIR, SPHINX_SHARED_LIBADD) + AC_DEFINE(LIBSPHINX_VERSION_ID,110,[ ]) + LIBSPHINX_VERSION_ID="110" + ],[],[ + -L$SPHINX_DIR/$PHP_LIBDIR -lm + ]) + + if test "x$LIBSPHINX_VERSION_ID" = "x"; then + PHP_CHECK_LIBRARY($LIBNAME,sphinx_set_select, + [ + PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $SPHINX_DIR/$PHP_LIBDIR, SPHINX_SHARED_LIBADD) + AC_DEFINE(LIBSPHINX_VERSION_ID,99,[ ]) + LIBSPHINX_VERSION_ID="99" + ],[],[ + -L$SPHINX_DIR/$PHP_LIBDIR -lm + ]) + fi + + if test "x$LIBSPHINX_VERSION_ID" = "x"; then + AC_DEFINE(LIBSPHINX_VERSION_ID,98,[ ]) + fi + + PHP_CHECK_LIBRARY($LIBNAME,sphinx_add_filter_string, + [ + AC_DEFINE(HAVE_SPHINX_ADD_FILTER_STRING,1,[ ]) + ],[],[ + -L$SPHINX_DIR/$PHP_LIBDIR -lm + ]) + + _SAVE_CFLAGS=$CFLAGS + CFLAGS="$CFLAGS -I$SPHINX_DIR/include" + AC_CACHE_CHECK([for new sphinx_set_ranking_mode() signature], ac_cv_3arg_setrankingmode, + [AC_TRY_COMPILE([#include <sphinxclient.h>], [sphinx_set_ranking_mode(0, 0, 0)], + ac_cv_3arg_setrankingmode=yes, ac_cv_3arg_setrankingmode=no)]) + if test "$ac_cv_3arg_setrankingmode" = yes; then + AC_DEFINE(HAVE_3ARG_SPHINX_SET_RANKING_MODE,1,[Whether we have 3 arg sphinx_set_ranking_mode()]) + fi + CFLAGS=$_SAVE_CFLAGS + + _SAVE_CPPFLAGS=$CPPFLAGS + CPPFLAGS="$CPPFLAGS -I$SPHINX_DIR/include" + + SPHINX_CHECK_ENUM(SPH_RANK_PROXIMITY) + SPHINX_CHECK_ENUM(SPH_RANK_MATCHANY) + SPHINX_CHECK_ENUM(SPH_RANK_FIELDMASK) + SPHINX_CHECK_ENUM(SPH_RANK_SPH04) + SPHINX_CHECK_ENUM(SPH_RANK_EXPR) + SPHINX_CHECK_ENUM(SPH_RANK_TOTAL) + + CPPFLAGS=$_SAVE_CPPFLAGS + + PHP_SUBST(SPHINX_SHARED_LIBADD) + + PHP_NEW_EXTENSION(sphinx, sphinx.c, $ext_shared) +fi | ||
[+] | Added | sphinx-1.3.99.1.tgz/config.w32 ^ |
@@ -0,0 +1,15 @@ +// $Id$ +// vim:ft=javascript + +ARG_WITH("sphinx", "for sphinx support", "yes"); + +if (PHP_SPHINX == "yes") { + if (CHECK_LIB("libsphinxclient.lib", "sphinx") && + CHECK_HEADER_ADD_INCLUDE("sphinxclient.h", "CFLAGS_SPHINX")) { + + ADD_FLAG("CFLAGS_SPHINX", "/D HAVE_3ARG_SPHINX_SET_RANKING_MODE=1"); + + EXTENSION("sphinx", "sphinx.c"); + } +} + | ||
[+] | Changed | sphinx-1.3.99.1.tgz/package.xml ^ |
@@ -1,43 +1,54 @@ <?xml version="1.0" encoding="UTF-8"?> -<package packagerversion="1.7.2" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 http://pear.php.net/dtd/tasks-1.0.xsd http://pear.php.net/dtd/package-2.0 http://pear.php.net/dtd/package-2.0.xsd"> +<package packagerversion="1.4.11" version="2.0" xmlns="http://pear.php.net/dtd/package-2.0" xmlns:tasks="http://pear.php.net/dtd/tasks-1.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://pear.php.net/dtd/tasks-1.0 +http://pear.php.net/dtd/tasks-1.0.xsd +http://pear.php.net/dtd/package-2.0 +http://pear.php.net/dtd/package-2.0.xsd"> <name>sphinx</name> <channel>pecl.php.net</channel> <summary>Client extension for Sphinx - opensource SQL full-text search engine</summary> - <description>This extension provides bindings for libsphinxclient, client library for Sphinx.</description> + <description> + This extension provides bindings for libsphinxclient, client library for Sphinx. + </description> <lead> <name>Antony Dovgal</name> <user>tony2001</user> <email>tony2001@php.net</email> <active>yes</active> </lead> - <date>2009-01-29</date> - <time>11:29:53</time> + <lead> + <name>Alexey Romanenko</name> + <user>santiago</user> + <email>santiago739@gmail.com</email> + <active>yes</active> + </lead> + <date>2014-07-06</date> + <time>19:00:00</time> <version> - <release>1.0.0</release> - <api>1.0.0</api> + <release>1.3.3</release> + <api>1.3.3</api> </version> <stability> <release>stable</release> <api>stable</api> </stability> <license uri="http://www.php.net/license">PHP</license> - <notes>- Added __sleep() and __wakeup() methods to prevent (un)serialization of SphinxClient instances. -- Fixed PECL bug #15033 (segfaults on SPARC because of unaligned read). -- Fixed PECL bug #14930 (configure fails on freebsd). (patch by nobleclem at fatalexception dot us) -- Fixed PECL bug #14752 (32-bit Client does not work with 64-bit ids). (nobleclem at fatalexception dot us, Tony)</notes> + <notes>- Added setFilterString() method, available only when built with sphinxclient lib >= 2.2.3. +- Fixed bug #67669 (SphinxClient::escapeString() is missing several symbols) + </notes> <contents> <dir name="/"> - <file md5sum="c664402670bd53a2ba39a1182f51259e" name="CREDITS" role="doc" /> - <file md5sum="2b6e68a834b9f76c2f0ebcd4d8f9ee71" name="config.m4" role="src" /> - <file md5sum="852a029f23080aa870633ce61e0fbe8e" name="config.w32" role="src" /> - <file md5sum="0b54a1196e704e90873ecabcdb73de67" name="sphinx.c" role="src" /> - <file md5sum="0427ae5fefdf1f2c007fbcec38d9900c" name="php_sphinx.h" role="src" /> - </dir> + <file name="CREDITS" role="doc" /> + <file name="LICENSE" role="doc" /> + <file name="config.m4" role="src" /> + <file name="config.w32" role="src" /> + <file name="sphinx.c" role="src" /> + <file name="php_sphinx.h" role="src" /> + </dir> <!-- / --> </contents> <dependencies> <required> <php> - <min>5.1.3</min> + <min>5.2.2</min> <max>6.0.0</max> <exclude>6.0.0</exclude> </php> @@ -52,30 +63,99 @@ </extsrcrelease> <changelog> <release> - <stability> - <release>beta</release> - <api>beta</api> - </stability> - <version> - <release>0.2.0</release> - <api>0.2.0</api> - </version> + <stability><release>stable</release><api>stable</api></stability> + <version><release>1.3.2</release><api>1.3.2</api></version> + <date>2014-05-06</date> + <notes>- Fixed build with older libsphinxclient versions (Dmitry Saprykin) +- Added LICENSE to the package. + </notes> + </release> + <release> + <stability><release>stable</release><api>stable</api></stability> + <version><release>1.3.1</release><api>1.3.1</api></version> + <date>2014-05-06</date> + <notes>- Fixed bug #67216 (segfault on setGroupBy()) (Dmitry Saprykin) +- Fixed bug #66272 (Some constants are not defined) + </notes> + </release> + <release> + <stability><release>stable</release><api>stable</api></stability> + <version><release>1.3.0</release><api>1.3.0</api></version> + <date>2013-04-04</date> + <notes>- Fixed setRankingMode's proto and add new ranking mode constants (patch by Michael Squires) +- Fixed segfault when reading object properties. +- Fixed bug #62026 (Second param in setRankingMode should be optional) + </notes> + </release> + <release> + <stability><release>stable</release><api>stable</api></stability> + <version><release>1.2.0</release><api>1.2.0</api></version> + <date>2012-04-03</date> + <notes>- Added mva support to updateAttributes(). +- Fixed build with 5_4. +- Fixed bug #61392 (build failure with new version of libsphinxclient) + </notes> + </release> + <release> + <stability><release>stable</release><api>stable</api></stability> + <version><release>1.1.0</release><api>1.1.0</api></version> + <date>2010-09-17</date> + <notes>- Added support for new API in sphinx 1.10 + - Fixed PECL bug #18325 (support 1.10-beta string attributes) + - Fixed PECL bug #17558 (time taken in search result was incorrect) + </notes> + </release> + <release> + <stability><release>stable</release><api>stable</api></stability> + <version><release>1.0.4</release><api>1.0.4</api></version> + <date>2010-02-26</date> + <notes>- Fixed PECL bug #17007 (incorrect query causes SEGFAULT)</notes> + </release> + <release> + <stability><release>stable</release><api>stable</api></stability> + <version><release>1.0.3</release><api>1.0.3</api></version> + <date>2010-01-12</date> + <notes>- Added support for open(), close(), status() and setOverride() available in sphinx 0.9.9 new API</notes> + </release> + <release> + <stability><release>stable</release><api>stable</api></stability> + <version><release>1.0.2</release><api>1.0.2</api></version> + <date>2009-12-03</date> + <notes>- Fixed crash when extending class doesn't call parent constructor.</notes> + </release> + <release> + <stability><release>stable</release><api>stable</api></stability> + <version><release>1.0.1</release><api>1.0.1</api></version> + <date>2009-11-03</date> + <notes>- Fixed build failure with PHP 5.1.x. +- Added support for setSelect(), available in sphinx 0.9.9 new API (patch by Olivier Poitrey) + </notes> + </release> + <release> + <stability><release>stable</release><api>stable</api></stability> + <version><release>1.0.0</release><api>1.0.0</api></version> + <date>2009-01-29</date> + <notes>- Added __sleep() and __wakeup() methods to prevent (un)serialization of SphinxClient instances. +- Fixed PECL bug #15033 (segfaults on SPARC because of unaligned read). +- Fixed PECL bug #14930 (configure fails on freebsd). (patch by nobleclem at fatalexception dot us) +- Fixed PECL bug #14752 (32-bit Client does not work with 64-bit ids). (nobleclem at fatalexception dot us, Tony) + </notes> + </release> + <release> + <stability><release>beta</release><api>beta</api></stability> + <version><release>0.2.0</release><api>0.2.0</api></version> <date>2008-07-31</date> <notes>- Updated SphinxClient::updateAttributes() to return number of updated attributes on success. - Updated SphinxClient::setIDRange() to accept integers, not floats. -- Updated SphinxClient::addQuery() to return integer on success.</notes> +- Updated SphinxClient::addQuery() to return integer on success. + </notes> </release> <release> - <stability> - <release>beta</release> - <api>beta</api> - </stability> - <version> - <release>0.1.0</release> - <api>0.1.0</api> - </version> + <stability><release>beta</release><api>beta</api></stability> + <version><release>0.1.0</release><api>0.1.0</api></version> <date>2008-07-21</date> - <notes>- Initial PECL release.</notes> + <notes>- Initial PECL release. + </notes> </release> </changelog> </package> | ||
[+] | Added | sphinx-1.3.99.1.tgz/php_sphinx.h ^ |
@@ -0,0 +1,46 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2008 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Antony Dovgal <tony at daylessday.org> | + | Based on Sphinx PHP API by Andrew Aksyonoff <shodan at shodan.ru> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifndef PHP_SPHINX_H +#define PHP_SPHINX_H + +extern zend_module_entry sphinx_module_entry; +#define phpext_sphinx_ptr &sphinx_module_entry + +#ifdef ZTS +#include "TSRM.h" +#endif + +PHP_MINIT_FUNCTION(sphinx); +PHP_MINFO_FUNCTION(sphinx); + +#define PHP_SPHINX_VERSION "1.4.0-dev" + +#endif /* PHP_SPHINX_H */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ | ||
[+] | Added | sphinx-1.3.99.1.tgz/sphinx.c ^ |
@@ -0,0 +1,2035 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2008 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_01.txt | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Antony Dovgal <tony at daylessday.org> | + | Based on Sphinx PHP API by Andrew Aksyonoff <shodan at shodan.ru> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "ext/standard/file.h" +#include "zend_operators.h" +#include "php_sphinx.h" + +#include <sphinxclient.h> + +static zend_class_entry *ce_sphinx_client; + +static zend_object_handlers php_sphinx_client_handlers; +static zend_object_handlers cannot_be_cloned; + +typedef struct _php_sphinx_client { + sphinx_client *sphinx; + zend_bool array_result; + zend_object std; +} php_sphinx_client; + +#ifdef COMPILE_DL_SPHINX +ZEND_GET_MODULE(sphinx) +#endif + +#ifndef E_RECOVERABLE_ERROR +#define E_RECOVERABLE_ERROR E_WARNING +#endif + +#define SPHINX_CONST(name) REGISTER_LONG_CONSTANT(#name, name, CONST_CS | CONST_PERSISTENT) + +#define SPHINX_INITIALIZED(c) \ + if (!(c) || !(c)->sphinx) { \ + php_error_docref(NULL, E_WARNING, "using uninitialized SphinxClient object"); \ + RETURN_FALSE; \ + } + +static inline php_sphinx_client *php_sphinx_client_object(zend_object *obj) { + return (php_sphinx_client *)((char*)(obj) - XtOffsetOf(php_sphinx_client, std)); +} + +#define sphinx_client(zv) php_sphinx_client_object(Z_OBJ_P(zv)) + +static void php_sphinx_client_obj_dtor(zend_object *object) /* {{{ */ +{ + php_sphinx_client *c = php_sphinx_client_object(object); + + sphinx_destroy(c->sphinx); + zend_object_std_dtor(&c->std); +} +/* }}} */ + +static zend_object *php_sphinx_client_new(zend_class_entry *ce) /* {{{ */ +{ + php_sphinx_client *c; + + c = ecalloc(1, sizeof(*c) + zend_object_properties_size(ce)); + zend_object_std_init(&c->std, ce); + object_properties_init(&c->std, ce); + c->std.handlers = &php_sphinx_client_handlers; + return &c->std; +} +/* }}} */ + +static zval *php_sphinx_client_read_property(zval *object, zval *member, int type, void **cache_slot, zval *rv) /* {{{ */ +{ + //php_sphinx_client *c; + zval tmp_member; + zval *retval; + zend_object_handlers *std_hnd; + + //c = sphinx_client(object); + + if (Z_TYPE_P(member) != IS_STRING) { + tmp_member = *member; + zval_copy_ctor(&tmp_member); + convert_to_string(&tmp_member); + member = &tmp_member; + } + + /* XXX we can either create retval ourselves (for custom properties) or use standard handlers */ + + std_hnd = zend_get_std_object_handlers(); + retval = std_hnd->read_property(object, member, type, cache_slot, rv); + + if (member == &tmp_member) { + zval_dtor(member); + } + return retval; +} +/* }}} */ + +static HashTable *php_sphinx_client_get_properties(zval *object) /* {{{ */ +{ + php_sphinx_client *c; + const char *warning, *error; + zval tmp; + HashTable *props; + + c = sphinx_client(object); + props = zend_std_get_properties(object); + + error = sphinx_error(c->sphinx); + ZVAL_STRING(&tmp, (char *)error); + zend_hash_str_update(props, "error", strlen("error"), &tmp); + + warning = sphinx_warning(c->sphinx); + ZVAL_STRING(&tmp, (char *)warning); + zend_hash_str_update(props, "warning", strlen("warning"), &tmp); + return c->std.properties; +} +/* }}} */ + +static void php_sphinx_result_to_array(php_sphinx_client *c, sphinx_result *result, zval *array) /* {{{ */ +{ + zval tmp; + int i, j; + + array_init(array); + + /* error */ + if (!result->error) { + add_assoc_string(array, "error", ""); + } else { + add_assoc_string(array, "error", (char *)(result->error)); + } + + /* warning */ + if (!result->warning) { + add_assoc_string(array, "warning", ""); + } else { + add_assoc_string(array, "warning", (char *)result->warning); + } + + /* status */ + add_assoc_long(array, "status", result->status); + + switch(result->status) { + case SEARCHD_OK: + /* ok, continue reading data */ + break; + case SEARCHD_WARNING: + /* this seems to be safe, too */ + break; + default: + /* libsphinxclient doesn't nullify the data + in case of error, so it's not safe to continue. */ + return; + } + + /* fields */ + array_init(&tmp); + + for (i = 0; i < result->num_fields; i++) { + add_next_index_string(&tmp, result->fields[i]); + } + add_assoc_zval(array, "fields", &tmp); + + /* attrs */ + array_init(&tmp); + + for (i = 0; i < result->num_attrs; i++) { +#if SIZEOF_LONG == 8 + add_assoc_long(&tmp, result->attr_names[i], result->attr_types[i]); +#else + double float_value; + char buf[128]; + + float_value = (double)result->attr_types[i]; + slprintf(buf, sizeof(buf), "%.0f", float_value); + add_assoc_string(&tmp, result->attr_names[i], buf); +#endif + } + add_assoc_zval(array, "attrs", &tmp); + + /* matches */ + if (result->num_matches) { + array_init(&tmp); + + for (i = 0; i < result->num_matches; i++) { + zval tmp_element, sub_element; + + array_init(&tmp_element); + + if (c->array_result) { + /* id */ +#if SIZEOF_LONG == 8 + add_assoc_long(&tmp_element, "id", sphinx_get_id(result, i)); +#else + double float_id; + char buf[128]; + + float_id = (double)sphinx_get_id(result, i); + slprintf(buf, sizeof(buf), "%.0f", float_id); + add_assoc_string(&tmp_element, "id", buf); +#endif + } + + /* weight */ + add_assoc_long(&tmp_element, "weight", sphinx_get_weight(result, i)); + + /* attrs */ + array_init(&sub_element); + + for (j = 0; j < result->num_attrs; j++) { + zval sub_sub_element; +#if SIZEOF_LONG != 8 + double float_value; + char buf[128]; +#endif + + switch(result->attr_types[j]) { + case SPH_ATTR_MULTI | SPH_ATTR_INTEGER: + { + int k; + unsigned int *mva = sphinx_get_mva(result, i, j); + unsigned int tmp, num; + + array_init(&sub_sub_element); + + if (!mva) { + break; + } + + memcpy(&num, mva, sizeof(unsigned int)); + + for (k = 1; k <= num; k++) { + mva++; + memcpy(&tmp, mva, sizeof(unsigned int)); +#if SIZEOF_LONG == 8 + add_next_index_long(&sub_sub_element, tmp); +#else + float_value = (double)tmp; + slprintf(buf, sizeof(buf), "%.0f", float_value); + add_next_index_string(&sub_sub_element, buf); +#endif + } + } break; + + case SPH_ATTR_FLOAT: + ZVAL_DOUBLE(&sub_sub_element, sphinx_get_float(result, i, j)); + break; +#if LIBSPHINX_VERSION_ID >= 110 + case SPH_ATTR_STRING: + ZVAL_STRING(&sub_sub_element, sphinx_get_string(result, i, j)); + break; +#endif + default: +#if SIZEOF_LONG == 8 + ZVAL_LONG(&sub_sub_element, sphinx_get_int(result, i, j)); +#else + float_value = (double)sphinx_get_int(result, i, j); + slprintf(buf, sizeof(buf), "%.0f", float_value); + ZVAL_STRING(&sub_sub_element, buf); +#endif + break; + } + + add_assoc_zval(&sub_element, result->attr_names[j], &sub_sub_element); + } + + add_assoc_zval(&tmp_element, "attrs", &sub_element); + + if (c->array_result) { + add_next_index_zval(&tmp, &tmp_element); + } else { +#if SIZEOF_LONG == 8 + add_index_zval(&tmp, sphinx_get_id(result, i), &tmp_element); +#else + char buf[128]; + double float_id; + int buf_len; + + float_id = (double)sphinx_get_id(result, i); + buf_len = slprintf(buf, sizeof(buf), "%.0f", float_id); + add_assoc_zval(tmp, buf, &tmp_element); +#endif + } + } + + add_assoc_zval(array, "matches", &tmp); + } + + /* total */ + add_assoc_long(array, "total", result->total); + + /* total_found */ + add_assoc_long(array, "total_found", result->total_found); + + /* time */ + add_assoc_double(array, "time", (double)result->time_msec/1000.0); + + /* words */ + if (result->num_words) { + zval tmp; + + array_init(&tmp); + for (i = 0; i < result->num_words; i++) { + zval sub_element; + + array_init(&sub_element); + + add_assoc_long(&sub_element, "docs", result->words[i].docs); + add_assoc_long(&sub_element, "hits", result->words[i].hits); + add_assoc_zval(&tmp, (char *)result->words[i].word, &sub_element); + } + add_assoc_zval(array, "words", &tmp); + } +} +/* }}} */ + + +/* {{{ proto void SphinxClient::__construct() */ +static PHP_METHOD(SphinxClient, __construct) +{ + php_sphinx_client *c; + + c = sphinx_client(getThis()); + + if (c->sphinx) { + /* called __construct() twice, bail out */ + return; + } + + c->sphinx = sphinx_create(1 /* copy string args */); + + sphinx_set_connect_timeout(c->sphinx, FG(default_socket_timeout)); +} +/* }}} */ + +/* {{{ proto bool SphinxClient::setServer(string server, int port) */ +static PHP_METHOD(SphinxClient, setServer) +{ + php_sphinx_client *c; + zend_long port; + char *server; + int res; + size_t server_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl", &server, &server_len, &port) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_set_server(c->sphinx, server, (int)port); + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool SphinxClient::setLimits(int offset, int limit[, int max_matches[, int cutoff]]) */ +static PHP_METHOD(SphinxClient, setLimits) +{ + php_sphinx_client *c; + zend_long offset, limit, max_matches = 1000, cutoff = 0; + int res; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll|ll", &offset, &limit, &max_matches, &cutoff) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_set_limits(c->sphinx, (int)offset, (int)limit, (int)max_matches, (int)cutoff); + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool SphinxClient::setMatchMode(int mode) */ +static PHP_METHOD(SphinxClient, setMatchMode) +{ + php_sphinx_client *c; + zend_long mode; + int res; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &mode) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_set_match_mode(c->sphinx, mode); + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool SphinxClient::setIndexWeights(array weights) */ +static PHP_METHOD(SphinxClient, setIndexWeights) +{ + php_sphinx_client *c; + zval *weights, *item; + int num_weights, res = 0, i; + int *index_weights; + char **index_names; + zend_string *string_key; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &weights) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + num_weights = zend_hash_num_elements(Z_ARRVAL_P(weights)); + if (!num_weights) { + /* check for empty array and return false right away */ + RETURN_FALSE; + } + + index_names = safe_emalloc(num_weights, sizeof(char *), 0); + index_weights = safe_emalloc(num_weights, sizeof(int), 0); + + /* reset num_weights, we'll reuse it count _real_ number of entries */ + num_weights = 0; + + ZEND_HASH_FOREACH_STR_KEY_VAL_IND(Z_ARRVAL_P(weights), string_key, item) { + if (!string_key) { + /* if the key is not string.. well.. you're screwed */ + break; + } + + index_names[num_weights] = estrndup(string_key->val, string_key->len); + index_weights[num_weights] = zval_get_long(item); + + num_weights++; + } ZEND_HASH_FOREACH_END(); + + if (num_weights) { + res = sphinx_set_index_weights(c->sphinx, num_weights, (const char **)index_names, index_weights); + } + + for (i = 0; i != num_weights; i++) { + efree(index_names[i]); + } + efree(index_names); + efree(index_weights); + + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +#if LIBSPHINX_VERSION_ID >= 99 +/* {{{ proto bool SphinxClient::setSelect(string clause) */ +static PHP_METHOD(SphinxClient, setSelect) +{ + php_sphinx_client *c; + char *clause; + int res; + size_t clause_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &clause, &clause_len) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_set_select(c->sphinx, clause); + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ +#endif + +/* {{{ proto bool SphinxClient::setIDRange(int min, int max) */ +static PHP_METHOD(SphinxClient, setIDRange) +{ + php_sphinx_client *c; + zend_long min, max; + int res; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ll", &min, &max) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_set_id_range(c->sphinx, (sphinx_uint64_t)min, (sphinx_uint64_t)max); + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool SphinxClient::setFilter(string attribute, array values[, bool exclude]) */ +static PHP_METHOD(SphinxClient, setFilter) +{ + php_sphinx_client *c; + zval *values, *item; + char *attribute; + int num_values, i = 0, res; + zend_bool exclude = 0; + sphinx_int64_t *u_values; + size_t attribute_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sa|b", &attribute, &attribute_len, &values, &exclude) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + num_values = zend_hash_num_elements(Z_ARRVAL_P(values)); + if (!num_values) { + RETURN_FALSE; + } + + u_values = safe_emalloc(num_values, sizeof(sphinx_int64_t), 0); + + ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(values), item) { + u_values[i] = (sphinx_int64_t)zval_get_double(item); + i++; + } ZEND_HASH_FOREACH_END(); + + res = sphinx_add_filter(c->sphinx, attribute, num_values, u_values, exclude ? 1 : 0); + efree(u_values); + + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +#ifdef HAVE_SPHINX_ADD_FILTER_STRING +/* {{{ proto bool SphinxClient::setFilterString(string attribute, string value[, bool exclude]) */ +static PHP_METHOD(SphinxClient, setFilterString) +{ + php_sphinx_client *c; + char *attribute, *value; + int res; + zend_bool exclude = 0; + size_t attribute_len, value_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ss|b", &attribute, &attribute_len, &value, &value_len, &exclude) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_add_filter_string(c->sphinx, attribute, value, exclude ? 1 : 0); + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ +#endif + +/* {{{ proto bool SphinxClient::setFilterRange(string attribute, int min, int max[, bool exclude]) */ +static PHP_METHOD(SphinxClient, setFilterRange) +{ + php_sphinx_client *c; + char *attribute; + int res; + zend_long min, max; + zend_bool exclude = 0; + size_t attribute_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sll|b", &attribute, &attribute_len, &min, &max, &exclude ) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_add_filter_range(c->sphinx, attribute, min, max, exclude); + + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool SphinxClient::setFilterFloatRange(string attribute, float min, float max[, bool exclude]) */ +static PHP_METHOD(SphinxClient, setFilterFloatRange) +{ + php_sphinx_client *c; + char *attribute; + int res; + double min, max; + zend_bool exclude = 0; + size_t attribute_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sdd|b", &attribute, &attribute_len, &min, &max, &exclude) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_add_filter_float_range(c->sphinx, attribute, min, max, exclude); + + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool SphinxClient::setGeoAnchor(string attrlat, string attrlong, float latitude, float longitude) */ +static PHP_METHOD(SphinxClient, setGeoAnchor) +{ + php_sphinx_client *c; + char *attrlat, *attrlong; + int res; + double latitude, longitude; + size_t attrlat_len, attrlong_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssdd", &attrlat, &attrlat_len, &attrlong, &attrlong_len, &latitude, &longitude) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_set_geoanchor(c->sphinx, attrlat, attrlong, latitude, longitude); + + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool SphinxClient::setGroupBy(string attribute, int func[, string groupsort]) */ +static PHP_METHOD(SphinxClient, setGroupBy) +{ + php_sphinx_client *c; + char *attribute, *groupsort = NULL; + int res; + zend_long func; + size_t attribute_len, groupsort_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sl|s", &attribute, &attribute_len, &func, &groupsort, &groupsort_len) == FAILURE) { + return; + } + + if (groupsort == NULL) { + groupsort = "@group desc"; + } + + if (func < SPH_GROUPBY_DAY || func > SPH_GROUPBY_ATTRPAIR) { + php_error_docref(NULL, E_WARNING, "invalid group func specified (%ld)", func); + RETURN_FALSE; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_set_groupby(c->sphinx, attribute, func, groupsort); + + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool SphinxClient::setGroupDistinct(string attribute) */ +static PHP_METHOD(SphinxClient, setGroupDistinct) +{ + php_sphinx_client *c; + char *attribute; + int res; + size_t attribute_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &attribute, &attribute_len) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_set_groupby_distinct(c->sphinx, attribute); + + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool SphinxClient::setRetries(int count[, int delay]) */ +static PHP_METHOD(SphinxClient, setRetries) +{ + php_sphinx_client *c; + zend_long count, delay = 0; + int res; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|l", &count, &delay) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_set_retries(c->sphinx, (int)count, (int)delay); + + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool SphinxClient::setMaxQueryTime(int qtime) */ +static PHP_METHOD(SphinxClient, setMaxQueryTime) +{ + php_sphinx_client *c; + zend_long qtime; + int res; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &qtime) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_set_max_query_time(c->sphinx, (int)qtime); + + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +#ifdef HAVE_3ARG_SPHINX_SET_RANKING_MODE +/* {{{ proto bool SphinxClient::setRankingMode(int ranker[, string ranking_expression]) */ +static PHP_METHOD(SphinxClient, setRankingMode) +{ + php_sphinx_client *c; + zend_long ranker; + int res; + char *rank_expr = NULL; + size_t rank_expr_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|s", &ranker, &rank_expr, &rank_expr_len) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_set_ranking_mode(c->sphinx, (int)ranker, rank_expr); + + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ +#else +/* {{{ proto bool SphinxClient::setRankingMode(int ranker) */ +static PHP_METHOD(SphinxClient, setRankingMode) +{ + php_sphinx_client *c; + zend_long ranker; + int res; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l", &ranker) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_set_ranking_mode(c->sphinx, (int)ranker); + + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ +#endif + +/* {{{ proto bool SphinxClient::setFieldWeights(array weights) */ +static PHP_METHOD(SphinxClient, setFieldWeights) +{ + php_sphinx_client *c; + zval *weights, *item; + int num_weights, res = 0, i; + int *field_weights; + char **field_names; + zend_string *string_key; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "a", &weights) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + num_weights = zend_hash_num_elements(Z_ARRVAL_P(weights)); + if (!num_weights) { + /* check for empty array and return false right away */ + RETURN_FALSE; + } + + field_names = safe_emalloc(num_weights, sizeof(char *), 0); + field_weights = safe_emalloc(num_weights, sizeof(int), 0); + + /* reset num_weights, we'll reuse it count _real_ number of entries */ + num_weights = 0; + + ZEND_HASH_FOREACH_STR_KEY_VAL_IND(Z_ARRVAL_P(weights), string_key, item) { + + if (!string_key) { + /* if the key is not string.. well.. you're screwed */ + break; + } + + field_names[num_weights] = estrndup(string_key->val, string_key->len); + field_weights[num_weights] = zval_get_long(item); + + num_weights++; + } ZEND_HASH_FOREACH_END(); + + if (num_weights) { + res = sphinx_set_field_weights(c->sphinx, num_weights, (const char **) field_names, field_weights); + } + + for (i = 0; i != num_weights; i++) { + efree(field_names[i]); + } + efree(field_names); + efree(field_weights); + + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool SphinxClient::setSortMode(int mode[, string sortby]) */ +static PHP_METHOD(SphinxClient, setSortMode) +{ + php_sphinx_client *c; + zend_long mode; + char *sortby = NULL; + int res; + size_t sortby_len; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "l|s", &mode, &sortby, &sortby_len) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_set_sort_mode(c->sphinx, (int)mode, sortby); + + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool SphinxClient::setConnectTimeout(float timeout) */ +static PHP_METHOD(SphinxClient, setConnectTimeout) +{ + php_sphinx_client *c; + double timeout; + int res; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "d", &timeout) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_set_connect_timeout(c->sphinx, timeout); + + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool SphinxClient::setArrayResult(bool array_result) */ +static PHP_METHOD(SphinxClient, setArrayResult) +{ + php_sphinx_client *c; + zend_bool array_result; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "b", &array_result) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + c->array_result = array_result; + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto int SphinxClient::updateAttributes(string index, array attributes, array values[, bool mva]) */ +static PHP_METHOD(SphinxClient, updateAttributes) +{ + php_sphinx_client *c; + zval *attributes, *values, *item; + char *index; + const char **attrs; + int attrs_num, values_num; + int res = 0; + sphinx_uint64_t *docids = NULL; + sphinx_int64_t *vals = NULL; + unsigned int *vals_mva = NULL; +#if LIBSPHINX_VERSION_ID >= 110 + int res_mva, values_mva_num, values_mva_size = 0; + zval *attr_value_mva; +#endif + int a = 0, i = 0, j = 0; + zend_bool mva = 0; + size_t index_len; + ulong id; + zend_string *str_id; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "saa|b", &index, &index_len, &attributes, &values, &mva) == FAILURE) { + return; + } + +#if LIBSPHINX_VERSION_ID < 110 + if (mva) { + php_error_docref(NULL, E_WARNING, "update mva attributes is not supported"); + RETURN_FALSE; + } +#endif + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + attrs_num = zend_hash_num_elements(Z_ARRVAL_P(attributes)); + + if (!attrs_num) { + php_error_docref(NULL, E_WARNING, "empty attributes array passed"); + RETURN_FALSE; + } + + values_num = zend_hash_num_elements(Z_ARRVAL_P(values)); + + if (!values_num) { + php_error_docref(NULL, E_WARNING, "empty values array passed"); + RETURN_FALSE; + } + + attrs = emalloc(sizeof(char *) * attrs_num); + ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(attributes), item) { + if (Z_TYPE_P(item) != IS_STRING) { + php_error_docref(NULL, E_WARNING, "non-string attributes are not allowed"); + break; + } + attrs[a] = Z_STRVAL_P(item); /* no copying here! */ + a++; + } ZEND_HASH_FOREACH_END(); + + /* cleanup on error */ + if (a != attrs_num) { + RETVAL_FALSE; + goto cleanup; + } + + docids = emalloc(sizeof(sphinx_int64_t) * values_num); + if (!mva) { + vals = safe_emalloc(values_num * attrs_num, sizeof(sphinx_int64_t), 0); + } + ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(values), id, str_id, item) { + zval *attr_value; + int failed = 0; + double float_id = 0; + unsigned char id_type; + + if (Z_TYPE_P(item) != IS_ARRAY) { + php_error_docref(NULL, E_WARNING, "value is not an array of attributes"); + break; + } + + if (zend_hash_num_elements(Z_ARRVAL_P(item)) != attrs_num) { + php_error_docref(NULL, E_WARNING, "number of values is not equal to the number of attributes"); + break; + } + + if (!str_id) { + /* ok */ + id_type = IS_LONG; + } else { + id_type = is_numeric_string(str_id->val, str_id->len, (long *)&id, &float_id, 0); + if (id_type == IS_LONG || id_type == IS_DOUBLE) { + /* ok */ + } else { + php_error_docref(NULL, E_WARNING, "document ID must be numeric"); + break; + } + } + + if (id_type == IS_LONG) { + docids[i] = (sphinx_uint64_t)id; + } else { /* IS_FLOAT */ + docids[i] = (sphinx_uint64_t)float_id; + } + + a = 0; + ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(item), attr_value) { + if (mva) { +#if LIBSPHINX_VERSION_ID >= 110 + if (Z_TYPE_P(attr_value) != IS_ARRAY) { + php_error_docref(NULL, E_WARNING, "attribute value must be an array"); + failed = 1; + break; + } + values_mva_num = zend_hash_num_elements(Z_ARRVAL_P(attr_value)); + if (values_mva_num > values_mva_size) { + values_mva_size = values_mva_num; + vals_mva = safe_erealloc(vals_mva, values_mva_size, sizeof(unsigned int), 0); + } + if (vals_mva) { + memset(vals_mva, 0, values_mva_size * sizeof(unsigned int)); + } + + j = 0; + ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(attr_value), attr_value_mva) { + if (Z_TYPE_P(attr_value_mva) != IS_LONG) { + php_error_docref(NULL, E_WARNING, "mva attribute value must be integer"); + failed = 1; + break; + } + vals_mva[j] = (unsigned int)Z_LVAL_P(attr_value_mva); + j++; + } ZEND_HASH_FOREACH_END(); + + if (failed) { + break; + } + + res_mva = sphinx_update_attributes_mva(c->sphinx, index, attrs[a], docids[i], values_mva_num, vals_mva); + + if (res_mva < 0) { + failed = 1; + break; + } +#endif + a++; + } else { + if (Z_TYPE_P(attr_value) != IS_LONG) { + php_error_docref(NULL, E_WARNING, "attribute value must be integer"); + failed = 1; + break; + } + vals[j] = (sphinx_int64_t)Z_LVAL_P(attr_value); + j++; + } + } ZEND_HASH_FOREACH_END(); + + if (failed) { + break; + } + + if (mva) { + res++; + } + i++; + } ZEND_HASH_FOREACH_END(); + + if (!mva && i != values_num) { + RETVAL_FALSE; + goto cleanup; + } + + if (!mva) { + res = sphinx_update_attributes(c->sphinx, index, (int)attrs_num, attrs, values_num, docids, vals); + } + + if (res < 0) { + RETVAL_FALSE; + } else { + RETVAL_LONG(res); + } + +cleanup: + efree(attrs); + if (docids) { + efree(docids); + } + if (vals) { + efree(vals); + } + if (vals_mva) { + efree(vals_mva); + } +} +/* }}} */ + +/* {{{ proto array SphinxClient::buildExcerpts(array docs, string index, string words[, array opts]) */ +static PHP_METHOD(SphinxClient, buildExcerpts) +{ + php_sphinx_client *c; + zval *docs_array, *opts_array = NULL, *item; + char *index, *words; + const char **docs; + sphinx_excerpt_options opts; + size_t index_len, words_len; + int docs_num, i = 0; + char **result; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ass|a", &docs_array, &index, &index_len, &words, &words_len, &opts_array) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + docs_num = zend_hash_num_elements(Z_ARRVAL_P(docs_array)); + + if (!docs_num) { + php_error_docref(NULL, E_WARNING, "empty documents array passed"); + RETURN_FALSE; + } + + docs = emalloc(sizeof(char *) * docs_num); + ZEND_HASH_FOREACH_VAL_IND(Z_ARRVAL_P(docs_array), item) { + if (Z_TYPE_P(item) != IS_STRING) { + php_error_docref(NULL, E_WARNING, "non-string documents are not allowed"); + break; + } + docs[i] = Z_STRVAL_P(item); /* no copying here! */ + i++; + } ZEND_HASH_FOREACH_END(); + + if (i != docs_num) { + RETVAL_FALSE; + goto cleanup; + } + +#define OPTS_EQUAL(str, txt) str->len == sizeof(txt) && memcmp(txt, str->val, sizeof(txt)) == 0 + + if (opts_array) { + zend_string *string_key; + + /* nullify everything */ + sphinx_init_excerpt_options(&opts); + ZEND_HASH_FOREACH_STR_KEY_VAL_IND(Z_ARRVAL_P(opts_array), string_key, item) { + + switch (Z_TYPE_P(item)) { + case IS_STRING: + case IS_LONG: + case IS_TRUE: + case IS_FALSE: + break; + default: + continue; /* ignore invalid options */ + } + + if (!string_key) { + continue; /* ignore invalid option names */ + } + + if (OPTS_EQUAL(string_key, "before_match")) { + SEPARATE_ZVAL(item); + convert_to_string_ex(item); + opts.before_match = Z_STRVAL_P(item); + } else if (OPTS_EQUAL(string_key, "after_match")) { + SEPARATE_ZVAL(item); + convert_to_string_ex(item); + opts.after_match = Z_STRVAL_P(item); + } else if (OPTS_EQUAL(string_key, "chunk_separator")) { + SEPARATE_ZVAL(item); + convert_to_string_ex(item); + opts.chunk_separator = Z_STRVAL_P(item); + } else if (OPTS_EQUAL(string_key, "limit")) { + SEPARATE_ZVAL(item); + convert_to_long_ex(item); + opts.limit = (int)Z_LVAL_P(item); + } else if (OPTS_EQUAL(string_key, "around")) { + SEPARATE_ZVAL(item); + convert_to_long_ex(item); + opts.around = (int)Z_LVAL_P(item); + } else if (OPTS_EQUAL(string_key, "exact_phrase")) { + SEPARATE_ZVAL(item); + convert_to_boolean_ex(item); + opts.exact_phrase = Z_LVAL_P(item); + } else if (OPTS_EQUAL(string_key, "single_passage")) { + SEPARATE_ZVAL(item); + convert_to_boolean_ex(item); + opts.single_passage = Z_LVAL_P(item); + } else if (OPTS_EQUAL(string_key, "use_boundaries")) { + SEPARATE_ZVAL(item); + convert_to_boolean_ex(item); + opts.use_boundaries = Z_LVAL_P(item); + } else if (OPTS_EQUAL(string_key, "weight_order")) { + SEPARATE_ZVAL(item); + convert_to_boolean_ex(item); + opts.weight_order = Z_LVAL_P(item); +#if LIBSPHINX_VERSION_ID >= 110 + } else if (OPTS_EQUAL(string_key, "query_mode")) { + SEPARATE_ZVAL(item); + convert_to_boolean_ex(item); + opts.query_mode = Z_LVAL_P(item); + } else if (OPTS_EQUAL(string_key, "force_all_words")) { + SEPARATE_ZVAL(item); + convert_to_boolean_ex(item); + opts.force_all_words = Z_LVAL_P(item); + } else if (OPTS_EQUAL(string_key, "limit_passages")) { + SEPARATE_ZVAL(item); + convert_to_long_ex(item); + opts.limit_passages = (int)Z_LVAL_P(item); + } else if (OPTS_EQUAL(string_key, "limit_words")) { + SEPARATE_ZVAL(item); + convert_to_long_ex(item); + opts.limit_words = (int)Z_LVAL_P(item); + } else if (OPTS_EQUAL(string_key, "start_passage_id")) { + SEPARATE_ZVAL(item); + convert_to_long_ex(item); + opts.start_passage_id = (int)Z_LVAL_P(item); + } else if (OPTS_EQUAL(string_key, "load_files")) { + SEPARATE_ZVAL(item); + convert_to_boolean_ex(item); + opts.load_files = Z_LVAL_P(item); + } else if (OPTS_EQUAL(string_key, "html_strip_mode")) { + SEPARATE_ZVAL(item); + convert_to_string_ex(item); + opts.html_strip_mode = Z_STRVAL_P(item); + } else if (OPTS_EQUAL(string_key, "allow_empty")) { + SEPARATE_ZVAL(item); + convert_to_boolean_ex(item); + opts.allow_empty = Z_LVAL_P(item); +#endif + } else { + /* ignore invalid option names */ + } + } ZEND_HASH_FOREACH_END(); + } + + if (opts_array) { + result = sphinx_build_excerpts(c->sphinx, docs_num, docs, index, words, &opts); + } else { + result = sphinx_build_excerpts(c->sphinx, docs_num, docs, index, words, NULL); + } + + if (!result) { + RETVAL_FALSE; + } else { + array_init(return_value); + for (i = 0; i < docs_num; i++) { + if (result[i] && result[i][0] != '\0') { + add_next_index_string(return_value, result[i]); + } else { + add_next_index_string(return_value, ""); + } + free(result[i]); + } + free(result); + } + +cleanup: + efree(docs); +} +/* }}} */ + +/* {{{ proto array SphinxClient::buildKeywords(string query, string index, bool hits) */ +static PHP_METHOD(SphinxClient, buildKeywords) +{ + php_sphinx_client *c; + char *query, *index; + size_t query_len, index_len; + zend_bool hits; + sphinx_keyword_info *result; + int i, num_keywords; + zval tmp; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "ssb", &query, &query_len, &index, &index_len, &hits) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + result = sphinx_build_keywords(c->sphinx, query, index, hits, &num_keywords); + if (!result || num_keywords <= 0) { + RETURN_FALSE; + } + + array_init(return_value); + for (i = 0; i < num_keywords; i++) { + array_init(&tmp); + + add_assoc_string(&tmp, "tokenized", result[i].tokenized); + add_assoc_string(&tmp, "normalized", result[i].normalized); + + if (hits) { + add_assoc_long(&tmp, "docs", result[i].num_docs); + add_assoc_long(&tmp, "hits", result[i].num_hits); + } + + add_next_index_zval(return_value, &tmp); + + free(result[i].tokenized); + free(result[i].normalized); + } + free(result); +} +/* }}} */ + +/* {{{ proto void SphinxClient::resetFilters() */ +static PHP_METHOD(SphinxClient, resetFilters) +{ + php_sphinx_client *c; + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + sphinx_reset_filters(c->sphinx); +} +/* }}} */ + +/* {{{ proto void SphinxClient::resetGroupBy() */ +static PHP_METHOD(SphinxClient, resetGroupBy) +{ + php_sphinx_client *c; + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + sphinx_reset_groupby(c->sphinx); +} +/* }}} */ + +/* {{{ proto string SphinxClient::getLastWarning() */ +static PHP_METHOD(SphinxClient, getLastWarning) +{ + php_sphinx_client *c; + const char *warning; + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + warning = sphinx_warning(c->sphinx); + if (!warning || !warning[0]) { + RETURN_EMPTY_STRING(); + } + RETURN_STRING((char *)warning); +} +/* }}} */ + +/* {{{ proto string SphinxClient::getLastError() */ +static PHP_METHOD(SphinxClient, getLastError) +{ + php_sphinx_client *c; + const char *error; + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + error = sphinx_error(c->sphinx); + if (!error || !error[0]) { + RETURN_EMPTY_STRING(); + } + RETURN_STRING((char *)error); +} +/* }}} */ + +/* {{{ proto array SphinxClient::query(string query[, string index[, string comment]]) */ +static PHP_METHOD(SphinxClient, query) +{ + php_sphinx_client *c; + char *query, *index = "*", *comment = ""; + size_t query_len, index_len, comment_len; + sphinx_result *result; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|ss", &query, &query_len, &index, &index_len, &comment, &comment_len) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + result = sphinx_query(c->sphinx, query, index, comment); + + if (!result) { + RETURN_FALSE; + } + + php_sphinx_result_to_array(c, result, return_value); +} + +/* }}} */ + +/* {{{ proto int SphinxClient::addQuery(string query[, string index[, string comment]]) */ +static PHP_METHOD(SphinxClient, addQuery) +{ + php_sphinx_client *c; + char *query, *index = "*", *comment = ""; + size_t query_len, index_len, comment_len, res; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s|ss", &query, &query_len, &index, &index_len, &comment, &comment_len) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_add_query(c->sphinx, query, index, comment); + + if (res < 0) { + RETURN_FALSE; + } + RETURN_LONG(res); +} + +/* }}} */ + +/* {{{ proto array SphinxClient::runQueries() */ +static PHP_METHOD(SphinxClient, runQueries) +{ + php_sphinx_client *c; + sphinx_result *results; + int i, num_results; + zval single_result; + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + results = sphinx_run_queries(c->sphinx); + + if (!results) { + RETURN_FALSE; + } + + num_results = sphinx_get_num_results(c->sphinx); + + array_init(return_value); + for (i = 0; i < num_results; i++) { + php_sphinx_result_to_array(c, &results[i], &single_result); + add_next_index_zval(return_value, &single_result); + } +} +/* }}} */ + +/* {{{ proto string SphinxClient::escapeString(string data) */ +static PHP_METHOD(SphinxClient, escapeString) +{ + char *str, *new_str, *source, *target; + size_t str_len, new_str_len, i; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "s", &str, &str_len) == FAILURE) { + return; + } + + if (!str_len) { + RETURN_EMPTY_STRING(); + } + + new_str = safe_emalloc(2, str_len, 1); + target = new_str; + source = str; + for (i = 0; i < str_len; i++) { + switch (*source) { + case '(': + case ')': + case '|': + case '-': + case '!': + case '@': + case '~': + case '"': + case '&': + case '/': + case '\\': + case '^': + case '$': + case '=': + case '<': + *target++ = '\\'; + *target++ = *source; + break; + default: + *target++ = *source; + break; + } + source++; + } + *target = '\0'; + + new_str_len = target - new_str; + new_str = erealloc(new_str, new_str_len + 1); + RETURN_STRINGL(new_str, new_str_len); + efree(new_str); +} +/* }}} */ + +#if LIBSPHINX_VERSION_ID >= 99 +/* {{{ proto bool SphinxClient::open() */ +static PHP_METHOD(SphinxClient, open) +{ + php_sphinx_client *c; + int res; + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_open(c->sphinx); + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool SphinxClient::close() */ +static PHP_METHOD(SphinxClient, close) +{ + php_sphinx_client *c; + int res; + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + res = sphinx_close(c->sphinx); + if (!res) { + RETURN_FALSE; + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto array SphinxClient::status() */ +static PHP_METHOD(SphinxClient, status) +{ + php_sphinx_client *c; + char **result; + int i, j, k, num_rows, num_cols; + zval tmp; + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + result = sphinx_status(c->sphinx, &num_rows, &num_cols); + + if (!result || num_rows <= 0) { + RETURN_FALSE; + } + + k = 0; + array_init(return_value); + for (i = 0; i < num_rows; i++) { + array_init(&tmp); + + for (j = 0; j < num_cols; j++, k++) { + add_next_index_string(&tmp, result[k]); + } + add_next_index_zval(return_value, &tmp); + } + sphinx_status_destroy(result, num_rows, num_cols); +} +/* }}} */ + +/* {{{ proto bool SphinxClient::setOverride(string attribute, int type, array values) */ +static PHP_METHOD(SphinxClient, setOverride) +{ + php_sphinx_client *c; + zval *values, *attr_value; + char *attribute; + zend_long type; + size_t attribute_len, values_num, i = 0; + int res; + sphinx_uint64_t *docids = NULL; + unsigned int *vals = NULL; + ulong id; + zend_string *str_id; + + if (zend_parse_parameters(ZEND_NUM_ARGS(), "sla", &attribute, &attribute_len, &type, &values) == FAILURE) { + return; + } + + c = sphinx_client(getThis()); + SPHINX_INITIALIZED(c) + + if (type != SPH_ATTR_INTEGER && type != SPH_ATTR_TIMESTAMP + && type != SPH_ATTR_BOOL && type != SPH_ATTR_FLOAT) { + php_error_docref(NULL, E_WARNING, "type must be scalar"); + RETURN_FALSE; + } + + values_num = zend_hash_num_elements(Z_ARRVAL_P(values)); + if (!values_num) { + php_error_docref(NULL, E_WARNING, "empty values array passed"); + RETURN_FALSE; + } + + docids = emalloc(sizeof(sphinx_uint64_t) * values_num); + vals = safe_emalloc(values_num, sizeof(unsigned int), 0); + ZEND_HASH_FOREACH_KEY_VAL_IND(Z_ARRVAL_P(values), id, str_id, attr_value) { + double float_id = 0; + unsigned char id_type; + + if (Z_TYPE_P(attr_value) != IS_LONG) { + php_error_docref(NULL, E_WARNING, "attribute value must be integer"); + break; + } + + if (!str_id) { + /* ok */ + id_type = IS_LONG; + } else { + id_type = is_numeric_string(str_id->val, str_id->len, (long *)&id, &float_id, 0); + if (id_type == IS_LONG || id_type == IS_DOUBLE) { + /* ok */ + } else { + php_error_docref(NULL, E_WARNING, "document ID must be numeric"); + break; + } + } + vals[i] = (sphinx_uint64_t)Z_LVAL_P(attr_value); + + if (id_type == IS_LONG) { + docids[i] = (sphinx_uint64_t)id; + } else { /* IS_FLOAT */ + docids[i] = (sphinx_uint64_t)float_id; + } + i++; + } ZEND_HASH_FOREACH_END(); + + if (i != values_num) { + RETVAL_FALSE; + goto cleanup; + } + + res = sphinx_add_override(c->sphinx, attribute, docids, values_num, vals); + if (!res) { + RETVAL_FALSE; + } else { + RETVAL_TRUE; + } + +cleanup: + if (docids) { + efree(docids); + } + if (vals) { + efree(vals); + } +} +/* }}} */ +#endif + +/* {{{ proto int SphinxClient::__sleep() */ +static PHP_METHOD(SphinxClient, __sleep) +{ + php_error_docref(NULL, E_RECOVERABLE_ERROR, "SphinxClient instance cannot be (un)serialized"); +} +/* }}} */ + +/* {{{ proto int SphinxClient::__wakeup() */ +static PHP_METHOD(SphinxClient, __wakeup) +{ + php_error_docref(NULL, E_RECOVERABLE_ERROR, "SphinxClient instance cannot be (un)serialized"); +} +/* }}} */ + +/* {{{ arginfo */ +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setserver, 0, 0, 2) + ZEND_ARG_INFO(0, server) + ZEND_ARG_INFO(0, port) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setlimits, 0, 0, 2) + ZEND_ARG_INFO(0, offset) + ZEND_ARG_INFO(0, limit) + ZEND_ARG_INFO(0, max_matches) + ZEND_ARG_INFO(0, cutoff) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setmatchmode, 0, 0, 1) + ZEND_ARG_INFO(0, mode) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setindexweights, 0, 0, 1) + ZEND_ARG_INFO(0, weights) +ZEND_END_ARG_INFO() + +#if LIBSPHINX_VERSION_ID >= 99 +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setselect, 0, 0, 1) + ZEND_ARG_INFO(0, clause) +ZEND_END_ARG_INFO() +#endif + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setidrange, 0, 0, 2) + ZEND_ARG_INFO(0, min) + ZEND_ARG_INFO(0, max) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setfilter, 0, 0, 2) + ZEND_ARG_INFO(0, attribute) + ZEND_ARG_INFO(0, values) + ZEND_ARG_INFO(0, exclude) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setfilterstring, 0, 0, 2) + ZEND_ARG_INFO(0, attribute) + ZEND_ARG_INFO(0, value) + ZEND_ARG_INFO(0, exclude) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setfilterrange, 0, 0, 3) + ZEND_ARG_INFO(0, attribute) + ZEND_ARG_INFO(0, min) + ZEND_ARG_INFO(0, max) + ZEND_ARG_INFO(0, exclude) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setgeoanchor, 0, 0, 4) + ZEND_ARG_INFO(0, attrlat) + ZEND_ARG_INFO(0, attrlong) + ZEND_ARG_INFO(0, latitude) + ZEND_ARG_INFO(0, longitude) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setgroupby, 0, 0, 2) + ZEND_ARG_INFO(0, attribute) + ZEND_ARG_INFO(0, func) + ZEND_ARG_INFO(0, groupsort) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setgroupdistinct, 0, 0, 1) + ZEND_ARG_INFO(0, attribute) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setretries, 0, 0, 1) + ZEND_ARG_INFO(0, count) + ZEND_ARG_INFO(0, delay) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setmaxquerytime, 0, 0, 1) + ZEND_ARG_INFO(0, qtime) +ZEND_END_ARG_INFO() + +#if LIBSPHINX_VERSION_ID >= 99 +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setoverride, 0, 0, 3) + ZEND_ARG_INFO(0, attribute) + ZEND_ARG_INFO(0, type) + ZEND_ARG_INFO(0, values) +ZEND_END_ARG_INFO() +#endif + +#if HAVE_3ARG_SPHINX_SET_RANKING_MODE +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setrankingmode, 0, 0, 1) + ZEND_ARG_INFO(0, ranker) + ZEND_ARG_INFO(0, rank_expression) +ZEND_END_ARG_INFO() +#else +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setrankingmode, 0, 0, 1) + ZEND_ARG_INFO(0, ranker) +ZEND_END_ARG_INFO() +#endif + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setsortmode, 0, 0, 1) + ZEND_ARG_INFO(0, mode) + ZEND_ARG_INFO(0, sortby) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setconnecttimeout, 0, 0, 1) + ZEND_ARG_INFO(0, timeout) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_setarrayresult, 0, 0, 1) + ZEND_ARG_INFO(0, array_result) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_updateattributes, 0, 0, 3) + ZEND_ARG_INFO(0, index) + ZEND_ARG_INFO(0, attributes) + ZEND_ARG_INFO(0, values) + ZEND_ARG_INFO(0, mva) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_buildexcerpts, 0, 0, 3) + ZEND_ARG_INFO(0, docs) + ZEND_ARG_INFO(0, index) + ZEND_ARG_INFO(0, words) + ZEND_ARG_INFO(0, opts) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_buildkeywords, 0, 0, 3) + ZEND_ARG_INFO(0, query) + ZEND_ARG_INFO(0, index) + ZEND_ARG_INFO(0, hits) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_query, 0, 0, 1) + ZEND_ARG_INFO(0, query) + ZEND_ARG_INFO(0, index) + ZEND_ARG_INFO(0, comment) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_sphinxclient__param_void, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_sphinxclient_escapestring, 0, 0, 1) + ZEND_ARG_INFO(0, data) +ZEND_END_ARG_INFO() +/* }}} */ + +static zend_function_entry sphinx_client_methods[] = { /* {{{ */ + PHP_ME(SphinxClient, __construct, arginfo_sphinxclient__param_void, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, addQuery, arginfo_sphinxclient_query, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, buildExcerpts, arginfo_sphinxclient_buildexcerpts, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, buildKeywords, arginfo_sphinxclient_buildkeywords, ZEND_ACC_PUBLIC) +#if LIBSPHINX_VERSION_ID >= 99 + PHP_ME(SphinxClient, close, arginfo_sphinxclient__param_void, ZEND_ACC_PUBLIC) +#endif + PHP_ME(SphinxClient, getLastError, arginfo_sphinxclient__param_void, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, getLastWarning, arginfo_sphinxclient__param_void, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, escapeString, arginfo_sphinxclient_escapestring, ZEND_ACC_PUBLIC) +#if LIBSPHINX_VERSION_ID >= 99 + PHP_ME(SphinxClient, open, arginfo_sphinxclient__param_void, ZEND_ACC_PUBLIC) +#endif + PHP_ME(SphinxClient, query, arginfo_sphinxclient_query, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, resetFilters, arginfo_sphinxclient__param_void, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, resetGroupBy, arginfo_sphinxclient__param_void, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, runQueries, arginfo_sphinxclient__param_void, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, setArrayResult, arginfo_sphinxclient_setarrayresult, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, setConnectTimeout, arginfo_sphinxclient_setconnecttimeout, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, setFieldWeights, arginfo_sphinxclient_setindexweights, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, setFilter, arginfo_sphinxclient_setfilter, ZEND_ACC_PUBLIC) +#ifdef HAVE_SPHINX_ADD_FILTER_STRING + PHP_ME(SphinxClient, setFilterString, arginfo_sphinxclient_setfilterstring, ZEND_ACC_PUBLIC) +#endif + PHP_ME(SphinxClient, setFilterFloatRange, arginfo_sphinxclient_setfilterrange, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, setFilterRange, arginfo_sphinxclient_setfilterrange, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, setGeoAnchor, arginfo_sphinxclient_setgeoanchor, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, setGroupBy, arginfo_sphinxclient_setgroupby, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, setGroupDistinct, arginfo_sphinxclient_setgroupdistinct, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, setIndexWeights, arginfo_sphinxclient_setindexweights, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, setIDRange, arginfo_sphinxclient_setidrange, ZEND_ACC_PUBLIC) +#if LIBSPHINX_VERSION_ID >= 99 + PHP_ME(SphinxClient, setSelect, arginfo_sphinxclient_setselect, ZEND_ACC_PUBLIC) +#endif + PHP_ME(SphinxClient, setLimits, arginfo_sphinxclient_setlimits, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, setMatchMode, arginfo_sphinxclient_setmatchmode, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, setMaxQueryTime, arginfo_sphinxclient_setmaxquerytime, ZEND_ACC_PUBLIC) +#if LIBSPHINX_VERSION_ID >= 99 + PHP_ME(SphinxClient, setOverride, arginfo_sphinxclient_setoverride, ZEND_ACC_PUBLIC) +#endif + PHP_ME(SphinxClient, setRankingMode, arginfo_sphinxclient_setrankingmode, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, setRetries, arginfo_sphinxclient_setretries, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, setServer, arginfo_sphinxclient_setserver, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, setSortMode, arginfo_sphinxclient_setsortmode, ZEND_ACC_PUBLIC) +#if LIBSPHINX_VERSION_ID >= 99 + PHP_ME(SphinxClient, status, arginfo_sphinxclient__param_void, ZEND_ACC_PUBLIC) +#endif + PHP_ME(SphinxClient, updateAttributes, arginfo_sphinxclient_updateattributes, ZEND_ACC_PUBLIC) + PHP_ME(SphinxClient, __sleep, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) + PHP_ME(SphinxClient, __wakeup, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL) + {NULL, NULL, NULL} +}; +/* }}} */ + +/* {{{ PHP_MINIT_FUNCTION + */ +PHP_MINIT_FUNCTION(sphinx) +{ + zend_class_entry ce; + + memcpy(&cannot_be_cloned, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + cannot_be_cloned.clone_obj = NULL; + + memcpy(&php_sphinx_client_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); + php_sphinx_client_handlers.clone_obj = NULL; + php_sphinx_client_handlers.read_property = php_sphinx_client_read_property; + php_sphinx_client_handlers.get_properties = php_sphinx_client_get_properties; + php_sphinx_client_handlers.free_obj = php_sphinx_client_obj_dtor; + php_sphinx_client_handlers.offset = XtOffsetOf(php_sphinx_client, std); + + INIT_CLASS_ENTRY(ce, "SphinxClient", sphinx_client_methods); + ce_sphinx_client = zend_register_internal_class(&ce); + ce_sphinx_client->create_object = php_sphinx_client_new; + + SPHINX_CONST(SEARCHD_OK); + SPHINX_CONST(SEARCHD_ERROR); + SPHINX_CONST(SEARCHD_RETRY); + SPHINX_CONST(SEARCHD_WARNING); + + SPHINX_CONST(SPH_MATCH_ALL); + SPHINX_CONST(SPH_MATCH_ANY); + SPHINX_CONST(SPH_MATCH_PHRASE); + SPHINX_CONST(SPH_MATCH_BOOLEAN); + SPHINX_CONST(SPH_MATCH_EXTENDED); + SPHINX_CONST(SPH_MATCH_FULLSCAN); + SPHINX_CONST(SPH_MATCH_EXTENDED2); + + SPHINX_CONST(SPH_RANK_PROXIMITY_BM25); + SPHINX_CONST(SPH_RANK_BM25); + SPHINX_CONST(SPH_RANK_NONE); + SPHINX_CONST(SPH_RANK_WORDCOUNT); +#ifdef HAVE_SPH_RANK_PROXIMITY + SPHINX_CONST(SPH_RANK_PROXIMITY); +#endif +#ifdef HAVE_SPH_RANK_MATCHANY + SPHINX_CONST(SPH_RANK_MATCHANY); +#endif +#ifdef HAVE_SPH_RANK_FIELDMASK + SPHINX_CONST(SPH_RANK_FIELDMASK); +#endif +#ifdef HAVE_SPH_RANK_SPH04 + SPHINX_CONST(SPH_RANK_SPH04); +#endif +#ifdef HAVE_SPH_RANK_EXPR + SPHINX_CONST(SPH_RANK_EXPR); +#endif +#ifdef HAVE_SPH_RANK_TOTAL + SPHINX_CONST(SPH_RANK_TOTAL); +#endif + + SPHINX_CONST(SPH_SORT_RELEVANCE); + SPHINX_CONST(SPH_SORT_ATTR_DESC); + SPHINX_CONST(SPH_SORT_ATTR_ASC); + SPHINX_CONST(SPH_SORT_TIME_SEGMENTS); + SPHINX_CONST(SPH_SORT_EXTENDED); + SPHINX_CONST(SPH_SORT_EXPR); + + SPHINX_CONST(SPH_FILTER_VALUES); + SPHINX_CONST(SPH_FILTER_RANGE); + SPHINX_CONST(SPH_FILTER_FLOATRANGE); + + SPHINX_CONST(SPH_ATTR_INTEGER); + SPHINX_CONST(SPH_ATTR_TIMESTAMP); + SPHINX_CONST(SPH_ATTR_ORDINAL); + SPHINX_CONST(SPH_ATTR_BOOL); + SPHINX_CONST(SPH_ATTR_FLOAT); + SPHINX_CONST(SPH_ATTR_MULTI); + + SPHINX_CONST(SPH_GROUPBY_DAY); + SPHINX_CONST(SPH_GROUPBY_WEEK); + SPHINX_CONST(SPH_GROUPBY_MONTH); + SPHINX_CONST(SPH_GROUPBY_YEAR); + SPHINX_CONST(SPH_GROUPBY_ATTR); + SPHINX_CONST(SPH_GROUPBY_ATTRPAIR); + + return SUCCESS; +} +/* }}} */ + +/* {{{ PHP_MINFO_FUNCTION + */ +PHP_MINFO_FUNCTION(sphinx) +{ + php_info_print_table_start(); + php_info_print_table_header(2, "sphinx support", "enabled"); + php_info_print_table_header(2, "Version", PHP_SPHINX_VERSION); + php_info_print_table_header(2, "Revision", "$Revision$"); + php_info_print_table_end(); +} +/* }}} */ + +static zend_function_entry sphinx_functions[] = { /* {{{ */ + {NULL, NULL, NULL} +}; +/* }}} */ + +/* {{{ sphinx_module_entry + */ +zend_module_entry sphinx_module_entry = { + STANDARD_MODULE_HEADER, + "sphinx", + sphinx_functions, + PHP_MINIT(sphinx), + NULL, + NULL, + NULL, + PHP_MINFO(sphinx), + PHP_SPHINX_VERSION, + STANDARD_MODULE_PROPERTIES +}; +/* }}} */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ | ||
[+] | Added | sphinx-1.3.99.1.tgz/tests ^ |
+(directory) | ||
[+] | Added | sphinx-1.3.99.1.tgz/tests/api ^ |
+(directory) | ||
[+] | Added | sphinx-1.3.99.1.tgz/tests/api/sphinxapi-1.10.php ^ |
@@ -0,0 +1,1688 @@ +<?php + +// +// $Id: sphinxapi.php 2376 2010-06-29 14:08:19Z shodan $ +// + +// +// Copyright (c) 2001-2010, Andrew Aksyonoff +// Copyright (c) 2008-2010, Sphinx Technologies Inc +// All rights reserved +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License. You should have +// received a copy of the GPL license along with this program; if you +// did not, you can find it at http://www.gnu.org/ +// + +///////////////////////////////////////////////////////////////////////////// +// PHP version of Sphinx searchd client (PHP API) +///////////////////////////////////////////////////////////////////////////// + +/// known searchd commands +define ( "SEARCHD_COMMAND_SEARCH", 0 ); +define ( "SEARCHD_COMMAND_EXCERPT", 1 ); +define ( "SEARCHD_COMMAND_UPDATE", 2 ); +define ( "SEARCHD_COMMAND_KEYWORDS", 3 ); +define ( "SEARCHD_COMMAND_PERSIST", 4 ); +define ( "SEARCHD_COMMAND_STATUS", 5 ); +define ( "SEARCHD_COMMAND_QUERY", 6 ); +define ( "SEARCHD_COMMAND_FLUSHATTRS", 7 ); + +/// current client-side command implementation versions +define ( "VER_COMMAND_SEARCH", 0x117 ); +define ( "VER_COMMAND_EXCERPT", 0x102 ); +define ( "VER_COMMAND_UPDATE", 0x102 ); +define ( "VER_COMMAND_KEYWORDS", 0x100 ); +define ( "VER_COMMAND_STATUS", 0x100 ); +define ( "VER_COMMAND_QUERY", 0x100 ); +define ( "VER_COMMAND_FLUSHATTRS", 0x100 ); + +/// known searchd status codes +define ( "SEARCHD_OK", 0 ); +define ( "SEARCHD_ERROR", 1 ); +define ( "SEARCHD_RETRY", 2 ); +define ( "SEARCHD_WARNING", 3 ); + +/// known match modes +define ( "SPH_MATCH_ALL", 0 ); +define ( "SPH_MATCH_ANY", 1 ); +define ( "SPH_MATCH_PHRASE", 2 ); +define ( "SPH_MATCH_BOOLEAN", 3 ); +define ( "SPH_MATCH_EXTENDED", 4 ); +define ( "SPH_MATCH_FULLSCAN", 5 ); +define ( "SPH_MATCH_EXTENDED2", 6 ); // extended engine V2 (TEMPORARY, WILL BE REMOVED) + +/// known ranking modes (ext2 only) +define ( "SPH_RANK_PROXIMITY_BM25", 0 ); ///< default mode, phrase proximity major factor and BM25 minor one +define ( "SPH_RANK_BM25", 1 ); ///< statistical mode, BM25 ranking only (faster but worse quality) +define ( "SPH_RANK_NONE", 2 ); ///< no ranking, all matches get a weight of 1 +define ( "SPH_RANK_WORDCOUNT", 3 ); ///< simple word-count weighting, rank is a weighted sum of per-field keyword occurence counts +define ( "SPH_RANK_PROXIMITY", 4 ); +define ( "SPH_RANK_MATCHANY", 5 ); +define ( "SPH_RANK_FIELDMASK", 6 ); +define ( "SPH_RANK_SPH04", 7 ); +define ( "SPH_RANK_TOTAL", 8 ); + +/// known sort modes +define ( "SPH_SORT_RELEVANCE", 0 ); +define ( "SPH_SORT_ATTR_DESC", 1 ); +define ( "SPH_SORT_ATTR_ASC", 2 ); +define ( "SPH_SORT_TIME_SEGMENTS", 3 ); +define ( "SPH_SORT_EXTENDED", 4 ); +define ( "SPH_SORT_EXPR", 5 ); + +/// known filter types +define ( "SPH_FILTER_VALUES", 0 ); +define ( "SPH_FILTER_RANGE", 1 ); +define ( "SPH_FILTER_FLOATRANGE", 2 ); + +/// known attribute types +define ( "SPH_ATTR_INTEGER", 1 ); +define ( "SPH_ATTR_TIMESTAMP", 2 ); +define ( "SPH_ATTR_ORDINAL", 3 ); +define ( "SPH_ATTR_BOOL", 4 ); +define ( "SPH_ATTR_FLOAT", 5 ); +define ( "SPH_ATTR_BIGINT", 6 ); +define ( "SPH_ATTR_STRING", 7 ); +define ( "SPH_ATTR_MULTI", 0x40000000 ); + +/// known grouping functions +define ( "SPH_GROUPBY_DAY", 0 ); +define ( "SPH_GROUPBY_WEEK", 1 ); +define ( "SPH_GROUPBY_MONTH", 2 ); +define ( "SPH_GROUPBY_YEAR", 3 ); +define ( "SPH_GROUPBY_ATTR", 4 ); +define ( "SPH_GROUPBY_ATTRPAIR", 5 ); + +// important properties of PHP's integers: +// - always signed (one bit short of PHP_INT_SIZE) +// - conversion from string to int is saturated +// - float is double +// - div converts arguments to floats +// - mod converts arguments to ints + +// the packing code below works as follows: +// - when we got an int, just pack it +// if performance is a problem, this is the branch users should aim for +// +// - otherwise, we got a number in string form +// this might be due to different reasons, but we assume that this is +// because it didn't fit into PHP int +// +// - factor the string into high and low ints for packing +// - if we have bcmath, then it is used +// - if we don't, we have to do it manually (this is the fun part) +// +// - x64 branch does factoring using ints +// - x32 (ab)uses floats, since we can't fit unsigned 32-bit number into an int +// +// unpacking routines are pretty much the same. +// - return ints if we can +// - otherwise format number into a string + +/// pack 64-bit signed +function sphPackI64 ( $v ) +{ + assert ( is_numeric($v) ); + + // x64 + if ( PHP_INT_SIZE>=8 ) + { + $v = (int)$v; + return pack ( "NN", $v>>32, $v&0xFFFFFFFF ); + } + + // x32, int + if ( is_int($v) ) + return pack ( "NN", $v < 0 ? -1 : 0, $v ); + + // x32, bcmath + if ( function_exists("bcmul") ) + { + if ( bccomp ( $v, 0 ) == -1 ) + $v = bcadd ( "18446744073709551616", $v ); + $h = bcdiv ( $v, "4294967296", 0 ); + $l = bcmod ( $v, "4294967296" ); + return pack ( "NN", (float)$h, (float)$l ); // conversion to float is intentional; int would lose 31st bit + } + + // x32, no-bcmath + $p = max(0, strlen($v) - 13); + $lo = abs((float)substr($v, $p)); + $hi = abs((float)substr($v, 0, $p)); + + $m = $lo + $hi*1316134912.0; // (10 ^ 13) % (1 << 32) = 1316134912 + $q = floor($m/4294967296.0); + $l = $m - ($q*4294967296.0); + $h = $hi*2328.0 + $q; // (10 ^ 13) / (1 << 32) = 2328 + + if ( $v<0 ) + { + if ( $l==0 ) + $h = 4294967296.0 - $h; + else + { + $h = 4294967295.0 - $h; + $l = 4294967296.0 - $l; + } + } + return pack ( "NN", $h, $l ); +} + +/// pack 64-bit unsigned +function sphPackU64 ( $v ) +{ + assert ( is_numeric($v) ); + + // x64 + if ( PHP_INT_SIZE>=8 ) + { + assert ( $v>=0 ); + + // x64, int + if ( is_int($v) ) + return pack ( "NN", $v>>32, $v&0xFFFFFFFF ); + + // x64, bcmath + if ( function_exists("bcmul") ) + { + $h = bcdiv ( $v, 4294967296, 0 ); + $l = bcmod ( $v, 4294967296 ); + return pack ( "NN", $h, $l ); + } + + // x64, no-bcmath + $p = max ( 0, strlen($v) - 13 ); + $lo = (int)substr ( $v, $p ); + $hi = (int)substr ( $v, 0, $p ); + + $m = $lo + $hi*1316134912; + $l = $m % 4294967296; + $h = $hi*2328 + (int)($m/4294967296); + + return pack ( "NN", $h, $l ); + } + + // x32, int + if ( is_int($v) ) + return pack ( "NN", 0, $v ); + + // x32, bcmath + if ( function_exists("bcmul") ) + { + $h = bcdiv ( $v, "4294967296", 0 ); + $l = bcmod ( $v, "4294967296" ); + return pack ( "NN", (float)$h, (float)$l ); // conversion to float is intentional; int would lose 31st bit + } + + // x32, no-bcmath + $p = max(0, strlen($v) - 13); + $lo = (float)substr($v, $p); + $hi = (float)substr($v, 0, $p); + + $m = $lo + $hi*1316134912.0; + $q = floor($m / 4294967296.0); + $l = $m - ($q * 4294967296.0); + $h = $hi*2328.0 + $q; + + return pack ( "NN", $h, $l ); +} + +// unpack 64-bit unsigned +function sphUnpackU64 ( $v ) +{ + list ( $hi, $lo ) = array_values ( unpack ( "N*N*", $v ) ); + + if ( PHP_INT_SIZE>=8 ) + { + if ( $hi<0 ) $hi += (1<<32); // because php 5.2.2 to 5.2.5 is totally fucked up again + if ( $lo<0 ) $lo += (1<<32); + + // x64, int + if ( $hi<=2147483647 ) + return ($hi<<32) + $lo; + + // x64, bcmath + if ( function_exists("bcmul") ) + return bcadd ( $lo, bcmul ( $hi, "4294967296" ) ); + + // x64, no-bcmath + $C = 100000; + $h = ((int)($hi / $C) << 32) + (int)($lo / $C); + $l = (($hi % $C) << 32) + ($lo % $C); + if ( $l>$C ) + { + $h += (int)($l / $C); + $l = $l % $C; + } + + if ( $h==0 ) + return $l; + return sprintf ( "%d%05d", $h, $l ); + } + + // x32, int + if ( $hi==0 ) + { + if ( $lo>0 ) + return $lo; + return sprintf ( "%u", $lo ); + } + + $hi = sprintf ( "%u", $hi ); + $lo = sprintf ( "%u", $lo ); + + // x32, bcmath + if ( function_exists("bcmul") ) + return bcadd ( $lo, bcmul ( $hi, "4294967296" ) ); + + // x32, no-bcmath + $hi = (float)$hi; + $lo = (float)$lo; + + $q = floor($hi/10000000.0); + $r = $hi - $q*10000000.0; + $m = $lo + $r*4967296.0; + $mq = floor($m/10000000.0); + $l = $m - $mq*10000000.0; + $h = $q*4294967296.0 + $r*429.0 + $mq; + + $h = sprintf ( "%.0f", $h ); + $l = sprintf ( "%07.0f", $l ); + if ( $h=="0" ) + return sprintf( "%.0f", (float)$l ); + return $h . $l; +} + +// unpack 64-bit signed +function sphUnpackI64 ( $v ) +{ + list ( $hi, $lo ) = array_values ( unpack ( "N*N*", $v ) ); + + // x64 + if ( PHP_INT_SIZE>=8 ) + { + if ( $hi<0 ) $hi += (1<<32); // because php 5.2.2 to 5.2.5 is totally fucked up again + if ( $lo<0 ) $lo += (1<<32); + + return ($hi<<32) + $lo; + } + + // x32, int + if ( $hi==0 ) + { + if ( $lo>0 ) + return $lo; + return sprintf ( "%u", $lo ); + } + // x32, int + elseif ( $hi==-1 ) + { + if ( $lo<0 ) + return $lo; + return sprintf ( "%.0f", $lo - 4294967296.0 ); + } + + $neg = ""; + $c = 0; + if ( $hi<0 ) + { + $hi = ~$hi; + $lo = ~$lo; + $c = 1; + $neg = "-"; + } + + $hi = sprintf ( "%u", $hi ); + $lo = sprintf ( "%u", $lo ); + + // x32, bcmath + if ( function_exists("bcmul") ) + return $neg . bcadd ( bcadd ( $lo, bcmul ( $hi, "4294967296" ) ), $c ); + + // x32, no-bcmath + $hi = (float)$hi; + $lo = (float)$lo; + + $q = floor($hi/10000000.0); + $r = $hi - $q*10000000.0; + $m = $lo + $r*4967296.0; + $mq = floor($m/10000000.0); + $l = $m - $mq*10000000.0 + $c; + $h = $q*4294967296.0 + $r*429.0 + $mq; + if ( $l==10000000 ) + { + $l = 0; + $h += 1; + } + + $h = sprintf ( "%.0f", $h ); + $l = sprintf ( "%07.0f", $l ); + if ( $h=="0" ) + return $neg . sprintf( "%.0f", (float)$l ); + return $neg . $h . $l; +} + + +function sphFixUint ( $value ) +{ + if ( PHP_INT_SIZE>=8 ) + { + // x64 route, workaround broken unpack() in 5.2.2+ + if ( $value<0 ) $value += (1<<32); + return $value; + } + else + { + // x32 route, workaround php signed/unsigned braindamage + return sprintf ( "%u", $value ); + } +} + + +/// sphinx searchd client class +class SphinxClient +{ + var $_host; ///< searchd host (default is "localhost") + var $_port; ///< searchd port (default is 9312) + var $_offset; ///< how many records to seek from result-set start (default is 0) + var $_limit; ///< how many records to return from result-set starting at offset (default is 20) + var $_mode; ///< query matching mode (default is SPH_MATCH_ALL) + var $_weights; ///< per-field weights (default is 1 for all fields) + var $_sort; ///< match sorting mode (default is SPH_SORT_RELEVANCE) + var $_sortby; ///< attribute to sort by (defualt is "") + var $_min_id; ///< min ID to match (default is 0, which means no limit) + var $_max_id; ///< max ID to match (default is 0, which means no limit) + var $_filters; ///< search filters + var $_groupby; ///< group-by attribute name + var $_groupfunc; ///< group-by function (to pre-process group-by attribute value with) + var $_groupsort; ///< group-by sorting clause (to sort groups in result set with) + var $_groupdistinct;///< group-by count-distinct attribute + var $_maxmatches; ///< max matches to retrieve + var $_cutoff; ///< cutoff to stop searching at (default is 0) + var $_retrycount; ///< distributed retries count + var $_retrydelay; ///< distributed retries delay + var $_anchor; ///< geographical anchor point + var $_indexweights; ///< per-index weights + var $_ranker; ///< ranking mode (default is SPH_RANK_PROXIMITY_BM25) + var $_maxquerytime; ///< max query time, milliseconds (default is 0, do not limit) + var $_fieldweights; ///< per-field-name weights + var $_overrides; ///< per-query attribute values overrides + var $_select; ///< select-list (attributes or expressions, with optional aliases) + + var $_error; ///< last error message + var $_warning; ///< last warning message + var $_connerror; ///< connection error vs remote error flag + + var $_reqs; ///< requests array for multi-query + var $_mbenc; ///< stored mbstring encoding + var $_arrayresult; ///< whether $result["matches"] should be a hash or an array + var $_timeout; ///< connect timeout + + ///////////////////////////////////////////////////////////////////////////// + // common stuff + ///////////////////////////////////////////////////////////////////////////// + + /// create a new client object and fill defaults + function SphinxClient () + { + // per-client-object settings + $this->_host = "localhost"; + $this->_port = 9312; + $this->_path = false; + $this->_socket = false; + + // per-query settings + $this->_offset = 0; + $this->_limit = 20; + $this->_mode = SPH_MATCH_ALL; + $this->_weights = array (); + $this->_sort = SPH_SORT_RELEVANCE; + $this->_sortby = ""; + $this->_min_id = 0; + $this->_max_id = 0; + $this->_filters = array (); + $this->_groupby = ""; + $this->_groupfunc = SPH_GROUPBY_DAY; + $this->_groupsort = "@group desc"; + $this->_groupdistinct= ""; + $this->_maxmatches = 1000; + $this->_cutoff = 0; + $this->_retrycount = 0; + $this->_retrydelay = 0; + $this->_anchor = array (); + $this->_indexweights= array (); + $this->_ranker = SPH_RANK_PROXIMITY_BM25; + $this->_maxquerytime= 0; + $this->_fieldweights= array(); + $this->_overrides = array(); + $this->_select = "*"; + + $this->_error = ""; // per-reply fields (for single-query case) + $this->_warning = ""; + $this->_connerror = false; + + $this->_reqs = array (); // requests storage (for multi-query case) + $this->_mbenc = ""; + $this->_arrayresult = false; + $this->_timeout = 0; + } + + function __destruct() + { + if ( $this->_socket !== false ) + fclose ( $this->_socket ); + } + + /// get last error message (string) + function GetLastError () + { + return $this->_error; + } + + /// get last warning message (string) + function GetLastWarning () + { + return $this->_warning; + } + + /// get last error flag (to tell network connection errors from searchd errors or broken responses) + function IsConnectError() + { + return $this->_connerror; + } + + /// set searchd host name (string) and port (integer) + function SetServer ( $host, $port = 0 ) + { + assert ( is_string($host) ); + if ( $host[0] == '/') + { + $this->_path = 'unix://' . $host; + return; + } + if ( substr ( $host, 0, 7 )=="unix://" ) + { + $this->_path = $host; + return; + } + + assert ( is_int($port) ); + $this->_host = $host; + $this->_port = $port; + $this->_path = ''; + + } + + /// set server connection timeout (0 to remove) + function SetConnectTimeout ( $timeout ) + { + assert ( is_numeric($timeout) ); + $this->_timeout = $timeout; + } + + + function _Send ( $handle, $data, $length ) + { + if ( feof($handle) || fwrite ( $handle, $data, $length ) !== $length ) + { + $this->_error = 'connection unexpectedly closed (timed out?)'; + $this->_connerror = true; + return false; + } + return true; + } + + ///////////////////////////////////////////////////////////////////////////// + + /// enter mbstring workaround mode + function _MBPush () + { + $this->_mbenc = ""; + if ( ini_get ( "mbstring.func_overload" ) & 2 ) + { + $this->_mbenc = mb_internal_encoding(); + mb_internal_encoding ( "latin1" ); + } + } + + /// leave mbstring workaround mode + function _MBPop () + { + if ( $this->_mbenc ) + mb_internal_encoding ( $this->_mbenc ); + } + + /// connect to searchd server + function _Connect () + { + if ( $this->_socket!==false ) + { + // we are in persistent connection mode, so we have a socket + // however, need to check whether it's still alive + if ( !@feof ( $this->_socket ) ) + return $this->_socket; + + // force reopen + $this->_socket = false; + } + + $errno = 0; + $errstr = ""; + $this->_connerror = false; + + if ( $this->_path ) + { + $host = $this->_path; + $port = 0; + } + else + { + $host = $this->_host; + $port = $this->_port; + } + + if ( $this->_timeout<=0 ) + $fp = @fsockopen ( $host, $port, $errno, $errstr ); + else + $fp = @fsockopen ( $host, $port, $errno, $errstr, $this->_timeout ); + + if ( !$fp ) + { + if ( $this->_path ) + $location = $this->_path; + else + $location = "{$this->_host}:{$this->_port}"; + + $errstr = trim ( $errstr ); + $this->_error = "connection to $location failed (errno=$errno, msg=$errstr)"; + $this->_connerror = true; + return false; + } + + // send my version + // this is a subtle part. we must do it before (!) reading back from searchd. + // because otherwise under some conditions (reported on FreeBSD for instance) + // TCP stack could throttle write-write-read pattern because of Nagle. + if ( !$this->_Send ( $fp, pack ( "N", 1 ), 4 ) ) + { + fclose ( $fp ); + $this->_error = "failed to send client protocol version"; + return false; + } + + // check version + list(,$v) = unpack ( "N*", fread ( $fp, 4 ) ); + $v = (int)$v; + if ( $v<1 ) + { + fclose ( $fp ); + $this->_error = "expected searchd protocol version 1+, got version '$v'"; + return false; + } + + return $fp; + } + + /// get and check response packet from searchd server + function _GetResponse ( $fp, $client_ver ) + { + $response = ""; + $len = 0; + + $header = fread ( $fp, 8 ); + if ( strlen($header)==8 ) + { + list ( $status, $ver, $len ) = array_values ( unpack ( "n2a/Nb", $header ) ); + $left = $len; + while ( $left>0 && !feof($fp) ) + { + $chunk = fread ( $fp, $left ); + if ( $chunk ) + { + $response .= $chunk; + $left -= strlen($chunk); + } + } + } + if ( $this->_socket === false ) + fclose ( $fp ); + + // check response + $read = strlen ( $response ); + if ( !$response || $read!=$len ) + { + $this->_error = $len + ? "failed to read searchd response (status=$status, ver=$ver, len=$len, read=$read)" + : "received zero-sized searchd response"; + return false; + } + + // check status + if ( $status==SEARCHD_WARNING ) + { + list(,$wlen) = unpack ( "N*", substr ( $response, 0, 4 ) ); + $this->_warning = substr ( $response, 4, $wlen ); + return substr ( $response, 4+$wlen ); + } + if ( $status==SEARCHD_ERROR ) + { + $this->_error = "searchd error: " . substr ( $response, 4 ); + return false; + } + if ( $status==SEARCHD_RETRY ) + { + $this->_error = "temporary searchd error: " . substr ( $response, 4 ); + return false; + } + if ( $status!=SEARCHD_OK ) + { + $this->_error = "unknown status code '$status'"; + return false; + } + + // check version + if ( $ver<$client_ver ) + { + $this->_warning = sprintf ( "searchd command v.%d.%d older than client's v.%d.%d, some options might not work", + $ver>>8, $ver&0xff, $client_ver>>8, $client_ver&0xff ); + } + + return $response; + } + + ///////////////////////////////////////////////////////////////////////////// + // searching + ///////////////////////////////////////////////////////////////////////////// + + /// set offset and count into result set, + /// and optionally set max-matches and cutoff limits + function SetLimits ( $offset, $limit, $max=0, $cutoff=0 ) + { + assert ( is_int($offset) ); + assert ( is_int($limit) ); + assert ( $offset>=0 ); + assert ( $limit>0 ); + assert ( $max>=0 ); + $this->_offset = $offset; + $this->_limit = $limit; + if ( $max>0 ) + $this->_maxmatches = $max; + if ( $cutoff>0 ) + $this->_cutoff = $cutoff; + } + + /// set maximum query time, in milliseconds, per-index + /// integer, 0 means "do not limit" + function SetMaxQueryTime ( $max ) + { + assert ( is_int($max) ); + assert ( $max>=0 ); + $this->_maxquerytime = $max; + } + + /// set matching mode + function SetMatchMode ( $mode ) + { + assert ( $mode==SPH_MATCH_ALL + || $mode==SPH_MATCH_ANY + || $mode==SPH_MATCH_PHRASE + || $mode==SPH_MATCH_BOOLEAN + || $mode==SPH_MATCH_EXTENDED + || $mode==SPH_MATCH_FULLSCAN + || $mode==SPH_MATCH_EXTENDED2 ); + $this->_mode = $mode; + } + + /// set ranking mode + function SetRankingMode ( $ranker ) + { + assert ( $ranker>=0 && $ranker<SPH_RANK_TOTAL ); + $this->_ranker = $ranker; + } + + /// set matches sorting mode + function SetSortMode ( $mode, $sortby="" ) + { + assert ( + $mode==SPH_SORT_RELEVANCE || + $mode==SPH_SORT_ATTR_DESC || + $mode==SPH_SORT_ATTR_ASC || + $mode==SPH_SORT_TIME_SEGMENTS || + $mode==SPH_SORT_EXTENDED || + $mode==SPH_SORT_EXPR ); + assert ( is_string($sortby) ); + assert ( $mode==SPH_SORT_RELEVANCE || strlen($sortby)>0 ); + + $this->_sort = $mode; + $this->_sortby = $sortby; + } + + /// bind per-field weights by order + /// DEPRECATED; use SetFieldWeights() instead + function SetWeights ( $weights ) + { + assert ( is_array($weights) ); + foreach ( $weights as $weight ) + assert ( is_int($weight) ); + + $this->_weights = $weights; + } + + /// bind per-field weights by name + function SetFieldWeights ( $weights ) + { + assert ( is_array($weights) ); + foreach ( $weights as $name=>$weight ) + { + assert ( is_string($name) ); + assert ( is_int($weight) ); + } + $this->_fieldweights = $weights; + } + + /// bind per-index weights by name + function SetIndexWeights ( $weights ) + { + assert ( is_array($weights) ); + foreach ( $weights as $index=>$weight ) + { + assert ( is_string($index) ); + assert ( is_int($weight) ); + } + $this->_indexweights = $weights; + } + + /// set IDs range to match + /// only match records if document ID is beetwen $min and $max (inclusive) + function SetIDRange ( $min, $max ) + { + assert ( is_numeric($min) ); + assert ( is_numeric($max) ); + assert ( $min<=$max ); + $this->_min_id = $min; + $this->_max_id = $max; + } + + /// set values set filter + /// only match records where $attribute value is in given set + function SetFilter ( $attribute, $values, $exclude=false ) + { + assert ( is_string($attribute) ); + assert ( is_array($values) ); + assert ( count($values) ); + + if ( is_array($values) && count($values) ) + { + foreach ( $values as $value ) + assert ( is_numeric($value) ); + + $this->_filters[] = array ( "type"=>SPH_FILTER_VALUES, "attr"=>$attribute, "exclude"=>$exclude, "values"=>$values ); + } + } + + /// set range filter + /// only match records if $attribute value is beetwen $min and $max (inclusive) + function SetFilterRange ( $attribute, $min, $max, $exclude=false ) + { + assert ( is_string($attribute) ); + assert ( is_numeric($min) ); + assert ( is_numeric($max) ); + assert ( $min<=$max ); + + $this->_filters[] = array ( "type"=>SPH_FILTER_RANGE, "attr"=>$attribute, "exclude"=>$exclude, "min"=>$min, "max"=>$max ); + } + + /// set float range filter + /// only match records if $attribute value is beetwen $min and $max (inclusive) + function SetFilterFloatRange ( $attribute, $min, $max, $exclude=false ) + { + assert ( is_string($attribute) ); + assert ( is_float($min) ); + assert ( is_float($max) ); + assert ( $min<=$max ); + + $this->_filters[] = array ( "type"=>SPH_FILTER_FLOATRANGE, "attr"=>$attribute, "exclude"=>$exclude, "min"=>$min, "max"=>$max ); + } + + /// setup anchor point for geosphere distance calculations + /// required to use @geodist in filters and sorting + /// latitude and longitude must be in radians + function SetGeoAnchor ( $attrlat, $attrlong, $lat, $long ) + { + assert ( is_string($attrlat) ); + assert ( is_string($attrlong) ); + assert ( is_float($lat) ); + assert ( is_float($long) ); + + $this->_anchor = array ( "attrlat"=>$attrlat, "attrlong"=>$attrlong, "lat"=>$lat, "long"=>$long ); + } + + /// set grouping attribute and function + function SetGroupBy ( $attribute, $func, $groupsort="@group desc" ) + { + assert ( is_string($attribute) ); + assert ( is_string($groupsort) ); + assert ( $func==SPH_GROUPBY_DAY + || $func==SPH_GROUPBY_WEEK + || $func==SPH_GROUPBY_MONTH + || $func==SPH_GROUPBY_YEAR + || $func==SPH_GROUPBY_ATTR + || $func==SPH_GROUPBY_ATTRPAIR ); + + $this->_groupby = $attribute; + $this->_groupfunc = $func; + $this->_groupsort = $groupsort; + } + + /// set count-distinct attribute for group-by queries + function SetGroupDistinct ( $attribute ) + { + assert ( is_string($attribute) ); + $this->_groupdistinct = $attribute; + } + + /// set distributed retries count and delay + function SetRetries ( $count, $delay=0 ) + { + assert ( is_int($count) && $count>=0 ); + assert ( is_int($delay) && $delay>=0 ); + $this->_retrycount = $count; + $this->_retrydelay = $delay; + } + + /// set result set format (hash or array; hash by default) + /// PHP specific; needed for group-by-MVA result sets that may contain duplicate IDs + function SetArrayResult ( $arrayresult ) + { + assert ( is_bool($arrayresult) ); + $this->_arrayresult = $arrayresult; + } + + /// set attribute values override + /// there can be only one override per attribute + /// $values must be a hash that maps document IDs to attribute values + function SetOverride ( $attrname, $attrtype, $values ) + { + assert ( is_string ( $attrname ) ); + assert ( in_array ( $attrtype, array ( SPH_ATTR_INTEGER, SPH_ATTR_TIMESTAMP, SPH_ATTR_BOOL, SPH_ATTR_FLOAT, SPH_ATTR_BIGINT ) ) ); + assert ( is_array ( $values ) ); + + $this->_overrides[$attrname] = array ( "attr"=>$attrname, "type"=>$attrtype, "values"=>$values ); + } + + /// set select-list (attributes or expressions), SQL-like syntax + function SetSelect ( $select ) + { + assert ( is_string ( $select ) ); + $this->_select = $select; + } + + ////////////////////////////////////////////////////////////////////////////// + + /// clear all filters (for multi-queries) + function ResetFilters () + { + $this->_filters = array(); + $this->_anchor = array(); + } + + /// clear groupby settings (for multi-queries) + function ResetGroupBy () + { + $this->_groupby = ""; + $this->_groupfunc = SPH_GROUPBY_DAY; + $this->_groupsort = "@group desc"; + $this->_groupdistinct= ""; + } + + /// clear all attribute value overrides (for multi-queries) + function ResetOverrides () + { + $this->_overrides = array (); + } + + ////////////////////////////////////////////////////////////////////////////// + + /// connect to searchd server, run given search query through given indexes, + /// and return the search results + function Query ( $query, $index="*", $comment="" ) + { + assert ( empty($this->_reqs) ); + + $this->AddQuery ( $query, $index, $comment ); + $results = $this->RunQueries (); + $this->_reqs = array (); // just in case it failed too early + + if ( !is_array($results) ) + return false; // probably network error; error message should be already filled + + $this->_error = $results[0]["error"]; + $this->_warning = $results[0]["warning"]; + if ( $results[0]["status"]==SEARCHD_ERROR ) + return false; + else + return $results[0]; + } + + /// helper to pack floats in network byte order + function _PackFloat ( $f ) + { + $t1 = pack ( "f", $f ); // machine order + list(,$t2) = unpack ( "L*", $t1 ); // int in machine order + return pack ( "N", $t2 ); + } + + /// add query to multi-query batch + /// returns index into results array from RunQueries() call + function AddQuery ( $query, $index="*", $comment="" ) + { + // mbstring workaround + $this->_MBPush (); + + // build request + $req = pack ( "NNNNN", $this->_offset, $this->_limit, $this->_mode, $this->_ranker, $this->_sort ); // mode and limits + $req .= pack ( "N", strlen($this->_sortby) ) . $this->_sortby; + $req .= pack ( "N", strlen($query) ) . $query; // query itself + $req .= pack ( "N", count($this->_weights) ); // weights + foreach ( $this->_weights as $weight ) + $req .= pack ( "N", (int)$weight ); + $req .= pack ( "N", strlen($index) ) . $index; // indexes + $req .= pack ( "N", 1 ); // id64 range marker + $req .= sphPackU64 ( $this->_min_id ) . sphPackU64 ( $this->_max_id ); // id64 range + + // filters + $req .= pack ( "N", count($this->_filters) ); + foreach ( $this->_filters as $filter ) + { + $req .= pack ( "N", strlen($filter["attr"]) ) . $filter["attr"]; + $req .= pack ( "N", $filter["type"] ); + switch ( $filter["type"] ) + { + case SPH_FILTER_VALUES: + $req .= pack ( "N", count($filter["values"]) ); + foreach ( $filter["values"] as $value ) + $req .= sphPackI64 ( $value ); + break; + + case SPH_FILTER_RANGE: + $req .= sphPackI64 ( $filter["min"] ) . sphPackI64 ( $filter["max"] ); + break; + + case SPH_FILTER_FLOATRANGE: + $req .= $this->_PackFloat ( $filter["min"] ) . $this->_PackFloat ( $filter["max"] ); + break; + + default: + assert ( 0 && "internal error: unhandled filter type" ); + } + $req .= pack ( "N", $filter["exclude"] ); + } + + // group-by clause, max-matches count, group-sort clause, cutoff count + $req .= pack ( "NN", $this->_groupfunc, strlen($this->_groupby) ) . $this->_groupby; + $req .= pack ( "N", $this->_maxmatches ); + $req .= pack ( "N", strlen($this->_groupsort) ) . $this->_groupsort; + $req .= pack ( "NNN", $this->_cutoff, $this->_retrycount, $this->_retrydelay ); + $req .= pack ( "N", strlen($this->_groupdistinct) ) . $this->_groupdistinct; + + // anchor point + if ( empty($this->_anchor) ) + { + $req .= pack ( "N", 0 ); + } else + { + $a =& $this->_anchor; + $req .= pack ( "N", 1 ); + $req .= pack ( "N", strlen($a["attrlat"]) ) . $a["attrlat"]; + $req .= pack ( "N", strlen($a["attrlong"]) ) . $a["attrlong"]; + $req .= $this->_PackFloat ( $a["lat"] ) . $this->_PackFloat ( $a["long"] ); + } + + // per-index weights + $req .= pack ( "N", count($this->_indexweights) ); + foreach ( $this->_indexweights as $idx=>$weight ) + $req .= pack ( "N", strlen($idx) ) . $idx . pack ( "N", $weight ); + + // max query time + $req .= pack ( "N", $this->_maxquerytime ); + + // per-field weights + $req .= pack ( "N", count($this->_fieldweights) ); + foreach ( $this->_fieldweights as $field=>$weight ) + $req .= pack ( "N", strlen($field) ) . $field . pack ( "N", $weight ); + + // comment + $req .= pack ( "N", strlen($comment) ) . $comment; + + // attribute overrides + $req .= pack ( "N", count($this->_overrides) ); + foreach ( $this->_overrides as $key => $entry ) + { + $req .= pack ( "N", strlen($entry["attr"]) ) . $entry["attr"]; + $req .= pack ( "NN", $entry["type"], count($entry["values"]) ); + foreach ( $entry["values"] as $id=>$val ) + { + assert ( is_numeric($id) ); + assert ( is_numeric($val) ); + + $req .= sphPackU64 ( $id ); + switch ( $entry["type"] ) + { + case SPH_ATTR_FLOAT: $req .= $this->_PackFloat ( $val ); break; + case SPH_ATTR_BIGINT: $req .= sphPackI64 ( $val ); break; + default: $req .= pack ( "N", $val ); break; + } + } + } + + // select-list + $req .= pack ( "N", strlen($this->_select) ) . $this->_select; + + // mbstring workaround + $this->_MBPop (); + + // store request to requests array + $this->_reqs[] = $req; + return count($this->_reqs)-1; + } + + /// connect to searchd, run queries batch, and return an array of result sets + function RunQueries () + { + if ( empty($this->_reqs) ) + { + $this->_error = "no queries defined, issue AddQuery() first"; + return false; + } + + // mbstring workaround + $this->_MBPush (); + + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop (); + return false; + } + + // send query, get response + $nreqs = count($this->_reqs); + $req = join ( "", $this->_reqs ); + $len = 4+strlen($req); + $req = pack ( "nnNN", SEARCHD_COMMAND_SEARCH, VER_COMMAND_SEARCH, $len, $nreqs ) . $req; // add header + + if ( !( $this->_Send ( $fp, $req, $len+8 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_SEARCH ) ) ) + { + $this->_MBPop (); + return false; + } + + // query sent ok; we can reset reqs now + $this->_reqs = array (); + + // parse and return response + return $this->_ParseSearchResponse ( $response, $nreqs ); + } + + /// parse and return search query (or queries) response + function _ParseSearchResponse ( $response, $nreqs ) + { + $p = 0; // current position + $max = strlen($response); // max position for checks, to protect against broken responses + + $results = array (); + for ( $ires=0; $ires<$nreqs && $p<$max; $ires++ ) + { + $results[] = array(); + $result =& $results[$ires]; + + $result["error"] = ""; + $result["warning"] = ""; + + // extract status + list(,$status) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $result["status"] = $status; + if ( $status!=SEARCHD_OK ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $message = substr ( $response, $p, $len ); $p += $len; + + if ( $status==SEARCHD_WARNING ) + { + $result["warning"] = $message; + } else + { + $result["error"] = $message; + continue; + } + } + + // read schema + $fields = array (); + $attrs = array (); + + list(,$nfields) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + while ( $nfields-->0 && $p<$max ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $fields[] = substr ( $response, $p, $len ); $p += $len; + } + $result["fields"] = $fields; + + list(,$nattrs) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + while ( $nattrs-->0 && $p<$max ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $attr = substr ( $response, $p, $len ); $p += $len; + list(,$type) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $attrs[$attr] = $type; + } + $result["attrs"] = $attrs; + + // read match count + list(,$count) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + list(,$id64) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + + // read matches + $idx = -1; + while ( $count-->0 && $p<$max ) + { + // index into result array + $idx++; + + // parse document id and weight + if ( $id64 ) + { + $doc = sphUnpackU64 ( substr ( $response, $p, 8 ) ); $p += 8; + list(,$weight) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + } + else + { + list ( $doc, $weight ) = array_values ( unpack ( "N*N*", + substr ( $response, $p, 8 ) ) ); + $p += 8; + $doc = sphFixUint($doc); + } + $weight = sprintf ( "%u", $weight ); + + // create match entry + if ( $this->_arrayresult ) + $result["matches"][$idx] = array ( "id"=>$doc, "weight"=>$weight ); + else + $result["matches"][$doc]["weight"] = $weight; + + // parse and create attributes + $attrvals = array (); + foreach ( $attrs as $attr=>$type ) + { + // handle 64bit ints + if ( $type==SPH_ATTR_BIGINT ) + { + $attrvals[$attr] = sphUnpackI64 ( substr ( $response, $p, 8 ) ); $p += 8; + continue; + } + + // handle floats + if ( $type==SPH_ATTR_FLOAT ) + { + list(,$uval) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + list(,$fval) = unpack ( "f*", pack ( "L", $uval ) ); + $attrvals[$attr] = $fval; + continue; + } + + // handle everything else as unsigned ints + list(,$val) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + if ( $type & SPH_ATTR_MULTI ) + { + $attrvals[$attr] = array (); + $nvalues = $val; + while ( $nvalues-->0 && $p<$max ) + { + list(,$val) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $attrvals[$attr][] = sphFixUint($val); + } + } else if ( $type==SPH_ATTR_STRING ) + { + $attrvals[$attr] = substr ( $response, $p, $val ); + $p += $val; + } else + { + $attrvals[$attr] = sphFixUint($val); + } + } + + if ( $this->_arrayresult ) + $result["matches"][$idx]["attrs"] = $attrvals; + else + $result["matches"][$doc]["attrs"] = $attrvals; + } + + list ( $total, $total_found, $msecs, $words ) = + array_values ( unpack ( "N*N*N*N*", substr ( $response, $p, 16 ) ) ); + $result["total"] = sprintf ( "%u", $total ); + $result["total_found"] = sprintf ( "%u", $total_found ); + $result["time"] = sprintf ( "%.3f", $msecs/1000 ); + $p += 16; + + while ( $words-->0 && $p<$max ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $word = substr ( $response, $p, $len ); $p += $len; + list ( $docs, $hits ) = array_values ( unpack ( "N*N*", substr ( $response, $p, 8 ) ) ); $p += 8; + $result["words"][$word] = array ( + "docs"=>sprintf ( "%u", $docs ), + "hits"=>sprintf ( "%u", $hits ) ); + } + } + + $this->_MBPop (); + return $results; + } + + ///////////////////////////////////////////////////////////////////////////// + // excerpts generation + ///////////////////////////////////////////////////////////////////////////// + + /// connect to searchd server, and generate exceprts (snippets) + /// of given documents for given query. returns false on failure, + /// an array of snippets on success + function BuildExcerpts ( $docs, $index, $words, $opts=array() ) + { + assert ( is_array($docs) ); + assert ( is_string($index) ); + assert ( is_string($words) ); + assert ( is_array($opts) ); + + $this->_MBPush (); + + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop(); + return false; + } + + ///////////////// + // fixup options + ///////////////// + + if ( !isset($opts["before_match"]) ) $opts["before_match"] = "<b>"; + if ( !isset($opts["after_match"]) ) $opts["after_match"] = "</b>"; + if ( !isset($opts["chunk_separator"]) ) $opts["chunk_separator"] = " ... "; + if ( !isset($opts["limit"]) ) $opts["limit"] = 256; + if ( !isset($opts["limit_passages"]) ) $opts["limit_passages"] = 0; + if ( !isset($opts["limit_words"]) ) $opts["limit_words"] = 0; + if ( !isset($opts["around"]) ) $opts["around"] = 5; + if ( !isset($opts["exact_phrase"]) ) $opts["exact_phrase"] = false; + if ( !isset($opts["single_passage"]) ) $opts["single_passage"] = false; + if ( !isset($opts["use_boundaries"]) ) $opts["use_boundaries"] = false; + if ( !isset($opts["weight_order"]) ) $opts["weight_order"] = false; + if ( !isset($opts["query_mode"]) ) $opts["query_mode"] = false; + if ( !isset($opts["force_all_words"]) ) $opts["force_all_words"] = false; + if ( !isset($opts["start_passage_id"]) ) $opts["start_passage_id"] = 1; + if ( !isset($opts["load_files"]) ) $opts["load_files"] = false; + if ( !isset($opts["html_strip_mode"]) ) $opts["html_strip_mode"] = "index"; + if ( !isset($opts["allow_empty"]) ) $opts["allow_empty"] = false; + + ///////////////// + // build request + ///////////////// + + // v.1.2 req + $flags = 1; // remove spaces + if ( $opts["exact_phrase"] ) $flags |= 2; + if ( $opts["single_passage"] ) $flags |= 4; + if ( $opts["use_boundaries"] ) $flags |= 8; + if ( $opts["weight_order"] ) $flags |= 16; + if ( $opts["query_mode"] ) $flags |= 32; + if ( $opts["force_all_words"] ) $flags |= 64; + if ( $opts["load_files"] ) $flags |= 128; + if ( $opts["allow_empty"] ) $flags |= 256; + $req = pack ( "NN", 0, $flags ); // mode=0, flags=$flags + $req .= pack ( "N", strlen($index) ) . $index; // req index + $req .= pack ( "N", strlen($words) ) . $words; // req words + + // options + $req .= pack ( "N", strlen($opts["before_match"]) ) . $opts["before_match"]; + $req .= pack ( "N", strlen($opts["after_match"]) ) . $opts["after_match"]; + $req .= pack ( "N", strlen($opts["chunk_separator"]) ) . $opts["chunk_separator"]; + $req .= pack ( "NN", (int)$opts["limit"], (int)$opts["around"] ); + $req .= pack ( "NNN", (int)$opts["limit_passages"], (int)$opts["limit_words"], (int)$opts["start_passage_id"] ); // v.1.2 + $req .= pack ( "N", strlen($opts["html_strip_mode"]) ) . $opts["html_strip_mode"]; + + // documents + $req .= pack ( "N", count($docs) ); + foreach ( $docs as $doc ) + { + assert ( is_string($doc) ); + $req .= pack ( "N", strlen($doc) ) . $doc; + } + + //////////////////////////// + // send query, get response + //////////////////////////// + + $len = strlen($req); + $req = pack ( "nnN", SEARCHD_COMMAND_EXCERPT, VER_COMMAND_EXCERPT, $len ) . $req; // add header + if ( !( $this->_Send ( $fp, $req, $len+8 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_EXCERPT ) ) ) + { + $this->_MBPop (); + return false; + } + + ////////////////// + // parse response + ////////////////// + + $pos = 0; + $res = array (); + $rlen = strlen($response); + for ( $i=0; $i<count($docs); $i++ ) + { + list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) ); + $pos += 4; + + if ( $pos+$len > $rlen ) + { + $this->_error = "incomplete reply"; + $this->_MBPop (); + return false; + } + $res[] = $len ? substr ( $response, $pos, $len ) : ""; + $pos += $len; + } + + $this->_MBPop (); + return $res; + } + + + ///////////////////////////////////////////////////////////////////////////// + // keyword generation + ///////////////////////////////////////////////////////////////////////////// + + /// connect to searchd server, and generate keyword list for a given query + /// returns false on failure, + /// an array of words on success + function BuildKeywords ( $query, $index, $hits ) + { + assert ( is_string($query) ); + assert ( is_string($index) ); + assert ( is_bool($hits) ); + + $this->_MBPush (); + + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop(); + return false; + } + + ///////////////// + // build request + ///////////////// + + // v.1.0 req + $req = pack ( "N", strlen($query) ) . $query; // req query + $req .= pack ( "N", strlen($index) ) . $index; // req index + $req .= pack ( "N", (int)$hits ); + + //////////////////////////// + // send query, get response + //////////////////////////// + + $len = strlen($req); + $req = pack ( "nnN", SEARCHD_COMMAND_KEYWORDS, VER_COMMAND_KEYWORDS, $len ) . $req; // add header + if ( !( $this->_Send ( $fp, $req, $len+8 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_KEYWORDS ) ) ) + { + $this->_MBPop (); + return false; + } + + ////////////////// + // parse response + ////////////////// + + $pos = 0; + $res = array (); + $rlen = strlen($response); + list(,$nwords) = unpack ( "N*", substr ( $response, $pos, 4 ) ); + $pos += 4; + for ( $i=0; $i<$nwords; $i++ ) + { + list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) ); $pos += 4; + $tokenized = $len ? substr ( $response, $pos, $len ) : ""; + $pos += $len; + + list(,$len) = unpack ( "N*", substr ( $response, $pos, 4 ) ); $pos += 4; + $normalized = $len ? substr ( $response, $pos, $len ) : ""; + $pos += $len; + + $res[] = array ( "tokenized"=>$tokenized, "normalized"=>$normalized ); + + if ( $hits ) + { + list($ndocs,$nhits) = array_values ( unpack ( "N*N*", substr ( $response, $pos, 8 ) ) ); + $pos += 8; + $res [$i]["docs"] = $ndocs; + $res [$i]["hits"] = $nhits; + } + + if ( $pos > $rlen ) + { + $this->_error = "incomplete reply"; + $this->_MBPop (); + return false; + } + } + + $this->_MBPop (); + return $res; + } + + function EscapeString ( $string ) + { + $from = array ( '\\', '(',')','|','-','!','@','~','"','&', '/', '^', '$', '=' ); + $to = array ( '\\\\', '\(','\)','\|','\-','\!','\@','\~','\"', '\&', '\/', '\^', '\$', '\=' ); + + return str_replace ( $from, $to, $string ); + } + + ///////////////////////////////////////////////////////////////////////////// + // attribute updates + ///////////////////////////////////////////////////////////////////////////// + + /// batch update given attributes in given rows in given indexes + /// returns amount of updated documents (0 or more) on success, or -1 on failure + function UpdateAttributes ( $index, $attrs, $values, $mva=false ) + { + // verify everything + assert ( is_string($index) ); + assert ( is_bool($mva) ); + + assert ( is_array($attrs) ); + foreach ( $attrs as $attr ) + assert ( is_string($attr) ); + + assert ( is_array($values) ); + foreach ( $values as $id=>$entry ) + { + assert ( is_numeric($id) ); + assert ( is_array($entry) ); + assert ( count($entry)==count($attrs) ); + foreach ( $entry as $v ) + { + if ( $mva ) + { + assert ( is_array($v) ); + foreach ( $v as $vv ) + assert ( is_int($vv) ); + } else + assert ( is_int($v) ); + } + } + + // build request + $this->_MBPush (); + $req = pack ( "N", strlen($index) ) . $index; + + $req .= pack ( "N", count($attrs) ); + foreach ( $attrs as $attr ) + { + $req .= pack ( "N", strlen($attr) ) . $attr; + $req .= pack ( "N", $mva ? 1 : 0 ); + } + + $req .= pack ( "N", count($values) ); + foreach ( $values as $id=>$entry ) + { + $req .= sphPackU64 ( $id ); + foreach ( $entry as $v ) + { + $req .= pack ( "N", $mva ? count($v) : $v ); + if ( $mva ) + foreach ( $v as $vv ) + $req .= pack ( "N", $vv ); + } + } + + // connect, send query, get response + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop (); + return -1; + } + + $len = strlen($req); + $req = pack ( "nnN", SEARCHD_COMMAND_UPDATE, VER_COMMAND_UPDATE, $len ) . $req; // add header + if ( !$this->_Send ( $fp, $req, $len+8 ) ) + { + $this->_MBPop (); + return -1; + } + + if (!( $response = $this->_GetResponse ( $fp, VER_COMMAND_UPDATE ) )) + { + $this->_MBPop (); + return -1; + } + + // parse response + list(,$updated) = unpack ( "N*", substr ( $response, 0, 4 ) ); + $this->_MBPop (); + return $updated; + } + + ///////////////////////////////////////////////////////////////////////////// + // persistent connections + ///////////////////////////////////////////////////////////////////////////// + + function Open() + { + if ( $this->_socket !== false ) + { + $this->_error = 'already connected'; + return false; + } + if ( !$fp = $this->_Connect() ) + return false; + + // command, command version = 0, body length = 4, body = 1 + $req = pack ( "nnNN", SEARCHD_COMMAND_PERSIST, 0, 4, 1 ); + if ( !$this->_Send ( $fp, $req, 12 ) ) + return false; + + $this->_socket = $fp; + return true; + } + + function Close() + { + if ( $this->_socket === false ) + { + $this->_error = 'not connected'; + return false; + } + + fclose ( $this->_socket ); + $this->_socket = false; + + return true; + } + + ////////////////////////////////////////////////////////////////////////// + // status + ////////////////////////////////////////////////////////////////////////// + + function Status () + { + $this->_MBPush (); + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop(); + return false; + } + + $req = pack ( "nnNN", SEARCHD_COMMAND_STATUS, VER_COMMAND_STATUS, 4, 1 ); // len=4, body=1 + if ( !( $this->_Send ( $fp, $req, 12 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_STATUS ) ) ) + { + $this->_MBPop (); + return false; + } + + $res = substr ( $response, 4 ); // just ignore length, error handling, etc + $p = 0; + list ( $rows, $cols ) = array_values ( unpack ( "N*N*", substr ( $response, $p, 8 ) ) ); $p += 8; + + $res = array(); + for ( $i=0; $i<$rows; $i++ ) + for ( $j=0; $j<$cols; $j++ ) + { + list(,$len) = unpack ( "N*", substr ( $response, $p, 4 ) ); $p += 4; + $res[$i][] = substr ( $response, $p, $len ); $p += $len; + } + + $this->_MBPop (); + return $res; + } + + ////////////////////////////////////////////////////////////////////////// + // flush + ////////////////////////////////////////////////////////////////////////// + + function FlushAttributes () + { + $this->_MBPush (); + if (!( $fp = $this->_Connect() )) + { + $this->_MBPop(); + return -1; + } + + $req = pack ( "nnN", SEARCHD_COMMAND_FLUSHATTRS, VER_COMMAND_FLUSHATTRS, 0 ); // len=0 + if ( !( $this->_Send ( $fp, $req, 8 ) ) || + !( $response = $this->_GetResponse ( $fp, VER_COMMAND_FLUSHATTRS ) ) ) + { + $this->_MBPop (); + return -1; + } + + $tag = -1; + if ( strlen($response)==4 ) + list(,$tag) = unpack ( "N*", $response ); + else + $this->_error = "unexpected response length"; + + $this->_MBPop (); + return $tag; + } +} + +// +// $Id: sphinxapi.php 2376 2010-06-29 14:08:19Z shodan $ +// | ||
[+] | Added | sphinx-1.3.99.1.tgz/tests/api_0.9.8.php ^ |
@@ -0,0 +1,88 @@ +<?php + +date_default_timezone_set('Europe/Moscow'); + +$cl = new SphinxClient (); + +$q = "test"; +$sql = ""; +$mode = SPH_MATCH_ALL; +$host = "localhost"; +$port = 9312; +$index = "test1"; +$groupby = ""; +$groupsort = "@group desc"; +$filter = "group_id"; +$filtervals = array(); +$distinct = ""; +$sortby = ""; +$limit = 20; +$ranker = SPH_RANK_PROXIMITY_BM25; + +//////////// +// do query +//////////// + +$cl->SetServer ( $host, $port ); +$cl->SetConnectTimeout ( 1 ); +$cl->SetArrayResult ( true ); +$cl->SetFieldWeights ( array ( 100, 1 ) ); +$cl->SetMatchMode ( $mode ); +if ( count($filtervals) ) $cl->SetFilter ( $filter, $filtervals ); +if ( $groupby ) $cl->SetGroupBy ( $groupby, SPH_GROUPBY_ATTR, $groupsort ); +if ( $sortby ) $cl->SetSortMode ( SPH_SORT_EXTENDED, $sortby ); +if ( $sortexpr ) $cl->SetSortMode ( SPH_SORT_EXPR, $sortexpr ); +if ( $distinct ) $cl->SetGroupDistinct ( $distinct ); +if ( $limit ) $cl->SetLimits ( 0, $limit, ( $limit>1000 ) ? $limit : 1000 ); +$cl->SetRankingMode ( $ranker ); +$res = $cl->Query ( $q, $index ); + +/////////////////////// +// print query results +/////////////////////// + +//print_r($res); + +if ( $res===false ) +{ + print "Query failed: " . $cl->GetLastError() . ".\n"; + +} else +{ + if ( $cl->GetLastWarning() ) + print "WARNING: " . $cl->GetLastWarning() . "\n\n"; + + print "Query '$q' retrieved $res[total] of $res[total_found] matches in $res[time] sec.\n"; + print "Query stats:\n"; + if ( is_array($res["words"]) ) + foreach ( $res["words"] as $word => $info ) + print " '$word' found $info[hits] times in $info[docs] documents\n"; + print "\n"; + + if ( is_array($res["matches"]) ) + { + $n = 1; + print "Matches:\n"; + foreach ( $res["matches"] as $docinfo ) + { + print "$n. doc_id=$docinfo[id], weight=$docinfo[weight]"; + foreach ( $res["attrs"] as $attrname => $attrtype ) + { + $value = $docinfo["attrs"][$attrname]; + if ( $attrtype & SPH_ATTR_MULTI ) + { + $value = "(" . join ( ",", $value ) .")"; + } else + { + if ( $attrtype==SPH_ATTR_TIMESTAMP ) + $value = date ( "Y-m-d H:i:s", $value ); + } + print ", $attrname=$value"; + } + print "\n"; + $n++; + } + } +} + + | ||
[+] | Added | sphinx-1.3.99.1.tgz/tests/api_0.9.9.php ^ |
@@ -0,0 +1,98 @@ +<?php + +date_default_timezone_set('Europe/Moscow'); + +$cl = new SphinxClient (); + +$q = "test"; +$sql = ""; +$mode = SPH_MATCH_ALL; +$host = "localhost"; +$port = 9312; +$index = "test1"; +$groupby = ""; +$groupsort = "@group desc"; +$filter = "group_id"; +$filtervals = array(); +$distinct = ""; +$sortby = ""; +$limit = 20; +$ranker = SPH_RANK_PROXIMITY_BM25; +$select = "group_id,title"; + +//////////// +// do query +//////////// + +/* +$cl->SetServer ( $host, $port ); +$cl->SetConnectTimeout ( 1 ); +$cl->Open(); +*/ +$cl->SetArrayResult ( true ); +$cl->SetFieldWeights ( array ( 100, 1 ) ); +$cl->SetMatchMode ( $mode ); + +if ( count($filtervals) ) $cl->SetFilter ( $filter, $filtervals ); +if ( $groupby ) $cl->SetGroupBy ( $groupby, SPH_GROUPBY_ATTR, $groupsort ); +if ( $sortby ) $cl->SetSortMode ( SPH_SORT_EXTENDED, $sortby ); +if ( $sortexpr ) $cl->SetSortMode ( SPH_SORT_EXPR, $sortexpr ); +if ( $distinct ) $cl->SetGroupDistinct ( $distinct ); +if ( $select ) $cl->SetSelect ( $select ); +if ( $limit ) $cl->SetLimits ( 0, $limit, ( $limit>1000 ) ? $limit : 1000 ); +$cl->SetRankingMode ( $ranker ); +$res = $cl->Query ( $q, $index ); + +/////////////////////// +// print query results +/////////////////////// + +//print_r($res); + +if ( $res===false ) +{ + print "Query failed: " . $cl->GetLastError() . ".\n"; + +} else +{ + if ( $cl->GetLastWarning() ) + print "WARNING: " . $cl->GetLastWarning() . "\n\n"; + + print "Query '$q' retrieved $res[total] of $res[total_found] matches in $res[time] sec.\n"; + print "Query stats:\n"; + if ( is_array($res["words"]) ) + foreach ( $res["words"] as $word => $info ) + print " '$word' found $info[hits] times in $info[docs] documents\n"; + print "\n"; + + if ( is_array($res["matches"]) ) + { + $n = 1; + print "Matches:\n"; + foreach ( $res["matches"] as $docinfo ) + { + print "$n. doc_id=$docinfo[id], weight=$docinfo[weight]"; + foreach ( $res["attrs"] as $attrname => $attrtype ) + { + $value = $docinfo["attrs"][$attrname]; + if ( $attrtype & SPH_ATTR_MULTI ) + { + $value = "(" . join ( ",", $value ) .")"; + } else + { + if ( $attrtype==SPH_ATTR_TIMESTAMP ) + $value = date ( "Y-m-d H:i:s", $value ); + } + print ", $attrname=$value"; + } + print "\n"; + $n++; + } + } +} +$cl->Close(); +print "\n"; + + + + | ||
[+] | Added | sphinx-1.3.99.1.tgz/tests/example.sql ^ |
@@ -0,0 +1,30 @@ +DROP TABLE IF EXISTS test.documents; +CREATE TABLE test.documents +( + id INTEGER PRIMARY KEY NOT NULL AUTO_INCREMENT, + group_id INTEGER NOT NULL, + group_id2 INTEGER NOT NULL, + date_added DATETIME NOT NULL, + title VARCHAR(255) NOT NULL, + content TEXT NOT NULL +); + +REPLACE INTO test.documents ( id, group_id, group_id2, date_added, title, content ) VALUES + ( 1, 1, 5, NOW(), 'test one', 'this is my test document number one. also checking search within phrases.' ), + ( 2, 1, 6, NOW(), 'test two', 'this is my test document number two' ), + ( 3, 2, 7, NOW(), 'another doc', 'this is another group' ), + ( 4, 2, 8, NOW(), 'doc number four', 'this is to test groups' ); + +DROP TABLE IF EXISTS test.tags; +CREATE TABLE test.tags +( + docid INTEGER NOT NULL, + tagid INTEGER NOT NULL, + UNIQUE(docid,tagid) +); + +INSERT INTO test.tags VALUES + (1,1), (1,3), (1,5), (1,7), + (2,6), (2,4), (2,2), + (3,15), + (4,7), (4,40); | ||
[+] | Added | sphinx-1.3.99.1.tgz/tests/pecl_17007.php ^ |
@@ -0,0 +1,7 @@ +<?php +$sphinx = new SphinxClient(); +$sphinx->setServer('localhost', 3312); +$sphinx->setMatchMode(SPH_MATCH_EXTENDED2); +$sphinx->addQuery('test)'); +$results = $sphinx->runQueries(); +var_dump($results); | ||
[+] | Added | sphinx-1.3.99.1.tgz/tests/pecl_18635.php ^ |
@@ -0,0 +1,14 @@ +<?php +$s = new SphinxClient; +$s->setServer('localhost',9312); +$s->setMatchMode(SPH_MATCH_ANY); +$s->setMaxQueryTime(3); + + +$result = $s->query('test'); +var_dump($result); + +if ($result === false) +{ + print "Query failed: " . $s->GetLastError() . ".\n"; +} | ||
[+] | Added | sphinx-1.3.99.1.tgz/tests/sphinx-0.9.9.conf ^ |
@@ -0,0 +1,53 @@ + +source src1 +{ + type = mysql + + sql_host = localhost + sql_user = test + sql_pass = + sql_db = test + sql_port = 3306 # optional, default is 3306 + + sql_query = SELECT id, group_id, group_id2, UNIX_TIMESTAMP(date_added) AS date_added, title, content \ + FROM documents + + sql_attr_uint = group_id + sql_attr_uint = group_id2 + sql_attr_timestamp = date_added + sql_attr_multi = uint mva from query; SELECT docid, tagid FROM tags + sql_attr_multi = uint mva2 from query; SELECT docid, tagid FROM tags + + sql_query_info = SELECT * FROM documents WHERE id=$id +} + + +index test1 +{ + source = src1 + path = /tmp/sphinx-0.9.9/var/data/test1 + docinfo = extern + charset_type = sbcs +} + + +indexer +{ + mem_limit = 32M +} + + +searchd +{ + listen = 9312 + listen = 9306:mysql41 + log = /tmp/sphinx-0.9.9/var/log/searchd.log + query_log = /tmp/sphinx-0.9.9/var/log/query.log + read_timeout = 5 + max_children = 30 + pid_file = /tmp/sphinx-0.9.9/var/log/searchd.pid + max_matches = 1000 + seamless_rotate = 1 + preopen_indexes = 0 + unlink_old = 1 +} | ||
[+] | Added | sphinx-1.3.99.1.tgz/tests/sphinx-1.10.conf ^ |
@@ -0,0 +1,69 @@ + +source src1 +{ + type = mysql + + sql_host = localhost + sql_user = test + sql_pass = + sql_db = test + sql_port = 3306 # optional, default is 3306 + + sql_query = SELECT id, group_id, group_id2, UNIX_TIMESTAMP(date_added) AS date_added, title, content \ + FROM documents + + sql_attr_uint = group_id + sql_attr_uint = group_id2 + sql_attr_timestamp = date_added + sql_attr_string = title + sql_attr_multi = uint mva from query; SELECT docid, tagid FROM tags + sql_attr_multi = uint mva2 from query; SELECT docid, tagid FROM tags + + sql_query_info = SELECT * FROM documents WHERE id=$id +} + + +index test1 +{ + source = src1 + path = /tmp/sphinx-1.10/var/data/test1 + docinfo = extern + charset_type = sbcs +} + + +index testrt +{ + type = rt + rt_mem_limit = 32M + + path = /tmp/sphinx-1.10/var/data/testrt + charset_type = utf-8 + + rt_field = title + rt_field = content + rt_attr_uint = gid +} + + +indexer +{ + mem_limit = 32M +} + + +searchd +{ + listen = 9312 + listen = 9306:mysql41 + log = /tmp/sphinx-1.10/var/log/searchd.log + query_log = /tmp/sphinx-1.10/var/log/query.log + read_timeout = 5 + max_children = 30 + pid_file = /tmp/sphinx-1.10/var/log/searchd.pid + max_matches = 1000 + seamless_rotate = 1 + preopen_indexes = 0 + unlink_old = 1 + workers = threads # for RT to work +} | ||
[+] | Added | sphinx-1.3.99.1.tgz/tests/test_1.10.php ^ |
@@ -0,0 +1,202 @@ +<?php + +require ( "api/sphinxapi-1.10.php" ); + +function test_query ( $client, $test_extras ) +{ + $override_docid = 4; + $override_value = 456; + $query = "test"; + $index = "test1"; + + $client->SetFieldWeights ( array ( 'title' => 100, 'content' => 1 ) ); + + if ( $test_extras ) + { + $client->SetOverride ( "group_id", SPH_ATTR_INTEGER, array ( $override_docid => $override_value) ); + $client->SetSelect ( "*, group_id*1000+@id*10 AS q" ); + } + + $client->SetArrayResult(true); + $res = $client->Query ( $query, $index ); + if ( $res === false ) + { + print "Query failed: " . $client->GetLastError() . ".\n"; + } + else + { + if ( $client->GetLastWarning() ) + print "WARNING: " . $client->GetLastWarning() . "\n\n"; + + print "Query '$query' retrieved $res[total] of $res[total_found] matches in $res[time] sec.\n"; + print "Query stats:\n"; + if ( is_array($res["words"]) ) + foreach ( $res["words"] as $word => $info ) + print " '$word' found $info[hits] times in $info[docs] documents\n"; + print "\n"; + + if ( is_array($res["matches"]) ) + { + $n = 1; + print "Matches:\n"; + foreach ( $res["matches"] as $docinfo ) + { + print "$n. doc_id=$docinfo[id], weight=$docinfo[weight]"; + foreach ( $res["attrs"] as $attrname => $attrtype ) + { + $value = $docinfo["attrs"][$attrname]; + if ( $attrtype & SPH_ATTR_MULTI ) + { + $value = "(" . join ( ",", $value ) .")"; + } + else + { + if ( $attrtype==SPH_ATTR_TIMESTAMP ) + $value = date ( "Y-m-d H:i:s", $value ); + } + print ", $attrname=$value"; + } + print "\n"; + $n++; + } + } + } + print "\n"; +} + +function test_excerpt ( $client ) +{ + $docs = array + ( + "this is my test text to be highlighted, and for the sake of the testing we need to pump its length somewhat", + "another test text to be highlighted, below limit", + "test number three, without phrase match", + "final test, not only without phrase match, but also above limit and with swapped phrase text test as well" + ); + $words = "test text"; + $index = "test1"; + $opts = array + ( + "chunk_separator" => " ... ", + "limit" => 60, + "around" => 3, + ); + + for ( $j=0; $j<2; $j++ ) + { + $opts["exact_phrase"] = $j; + print "exact_phrase=$j\n" ; + + $res = $client->BuildExcerpts ( $docs, $index, $words, $opts ); + if ( !$res ) + { + print "query failed: " . $client->GetLastError() . ".\n" ; + } + else + { + $n = 0; + foreach ( $res as $entry ) + { + $n++; + print "n=$n, res=$entry\n"; + } + } + print "\n"; + } +} + +function test_update ( $client ) +{ + $attrs = array( "group_id" , "group_id2" ); + $vals = array( 2 => array ( 22, 33 ) , 4 => array ( 444, 555 ) ); + + $res = $client->UpdateAttributes( "test1", $attrs, $vals); + if ( $res < 0 ) + print "query failed: " . $client->GetLastError() . ".\n\n"; + else + print "update success, $res rows updated\n\n"; +} + +function test_update_mva ( $client ) +{ + $attrs = array ( "mva" , "mva2" ); + $vals = array ( + 1 => array( array ( 123, 456 ) , array ( 321 ) ) , + 2 => array( array ( 78, 910, 11 ) , array ( 87, 12 ) ), + 4 => array( array ( 55 ) , array ( 66 , 77 ) ) + ); + + $res = $client->UpdateAttributes( "test1", $attrs, $vals, true ); + if ( $res === false || $res < 0 ) + print "query mva failed: " . $client->GetLastError() . ".\n\n"; + else + print "update mva success, $res rows updated\n\n"; +} + +function test_keywords ( $client ) +{ + $words = $client->BuildKeywords("hello test one", "test1", true); + + if ( !$words ) + { + print "build_keywords failed: " . $client->GetLastError() . "\n\n" ; + } + else + { + print "build_keywords result:\n"; + + $n = 0; + foreach ( $words as $entry ) + { + $n++; + printf ( "%d. tokenized=%s, normalized=%s, docs=%d, hits=%d\n", $n, + $entry['tokenized'], $entry['normalized'], + $entry['docs'], $entry['hits'] ); + } + print "\n"; + } +} + +function test_status ( $client ) +{ + $status = $client->Status(); + if ( !$status ) + { + print "status failed: " . $client->GetLastError() . "\n\n"; + } + + foreach ( $status as $item ) + { + print "$item[0]: $item[1]\n"; + } + print "\n"; +} + +date_default_timezone_set('Europe/Moscow'); + +$host = "localhost"; +$port = 9312; + +$client = new SphinxClient (); +$client->SetServer ( $host, $port ); + +test_query ( $client, false ); +test_excerpt ( $client ); +test_update ( $client ); +test_update_mva ( $client ); +test_query ( $client, false ); + +test_keywords ( $client ); +test_query ( $client, true ); + +$client->Open(); +test_update ( $client ); +test_update ( $client ); +test_query ( $client, false ); +test_query ( $client, false ); +$client->Close(); + +test_status ( $client ); + + + |