├── config.w32 ├── test.php ├── .gitignore ├── README.md ├── LICENSE ├── config.m4 ├── php_geohash.h ├── geohash_lib.c └── geohash.c /config.w32: -------------------------------------------------------------------------------- 1 | // $Id$ 2 | // vim:ft=javascript 3 | 4 | // If your extension references something external, use ARG_WITH 5 | // ARG_WITH("geohash", "for geohash support", "no"); 6 | 7 | // Otherwise, use ARG_ENABLE 8 | // ARG_ENABLE("geohash", "enable geohash support", "no"); 9 | 10 | if (PHP_GEOHASH != "no") { 11 | EXTENSION("geohash", "geohash.c"); 12 | } 13 | 14 | -------------------------------------------------------------------------------- /test.php: -------------------------------------------------------------------------------- 1 | > /etc/php.ini 18 | 19 | ``` 20 | 21 | 22 | ## Example: 23 | 24 | Geohash::decode(geohash string); 25 | 26 | Geohash::encode(latitude,longtitude); 27 | 28 | Geohash::encode(latitude,longtitude,precision=12); 29 | 30 | ```php 31 | 35 | ``` 36 | ## output: 37 | 38 | ```php 39 | Array 40 | ( 41 | [latitude] => 30.635780068114 42 | [longitude] => 104.03160111979 43 | ) 44 | 45 | wm3yr31d2524 46 | 47 | ``` 48 | 49 | ##contact 50 | e-mail: love(a)taogogo.info 51 | 52 | ##docs 53 | 54 | google专利: http://www.google.fr/patents/US20130097163 55 | 56 | 维基百科: http://en.wikipedia.org/wiki/Geohash 57 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2010 Taogogo(www.taogogo.info) 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /config.m4: -------------------------------------------------------------------------------- 1 | dnl $Id$ 2 | dnl config.m4 for extension geohash 3 | 4 | dnl Comments in this file start with the string 'dnl'. 5 | dnl Remove where necessary. This file will not work 6 | dnl without editing. 7 | 8 | dnl If your extension references something external, use with: 9 | 10 | PHP_ARG_WITH(geohash, for geohash support, 11 | Make sure that the comment is aligned: 12 | [ --with-geohash Include geohash support]) 13 | 14 | dnl Otherwise use enable: 15 | 16 | dnl PHP_ARG_ENABLE(geohash, whether to enable geohash support, 17 | dnl Make sure that the comment is aligned: 18 | dnl [ --enable-geohash Enable geohash support]) 19 | 20 | if test "$PHP_GEOHASH" != "no"; then 21 | dnl Write more exageohashes of tests here... 22 | 23 | dnl # --with-geohash -> check with-path 24 | dnl SEARCH_PATH="/usr/local /usr" # you might want to change this 25 | dnl SEARCH_FOR="/include/geohash.h" # you most likely want to change this 26 | dnl if test -r $PHP_GEOHASH/$SEARCH_FOR; then # path given as parameter 27 | dnl GEOHASH_DIR=$PHP_GEOHASH 28 | dnl else # search default path list 29 | dnl AC_MSG_CHECKING([for geohash files in default path]) 30 | dnl for i in $SEARCH_PATH ; do 31 | dnl if test -r $i/$SEARCH_FOR; then 32 | dnl GEOHASH_DIR=$i 33 | dnl AC_MSG_RESULT(found in $i) 34 | dnl fi 35 | dnl done 36 | dnl fi 37 | dnl 38 | dnl if test -z "$GEOHASH_DIR"; then 39 | dnl AC_MSG_RESULT([not found]) 40 | dnl AC_MSG_ERROR([Please reinstall the geohash distribution]) 41 | dnl fi 42 | 43 | dnl # --with-geohash -> add include path 44 | dnl PHP_ADD_INCLUDE($GEOHASH_DIR/include) 45 | 46 | dnl # --with-geohash -> check for lib and symbol presence 47 | dnl LIBNAME=geohash # you may want to change this 48 | dnl LIBSYMBOL=geohash # you most likely want to change this 49 | 50 | dnl PHP_CHECK_LIBRARY($LIBNAME,$LIBSYMBOL, 51 | dnl [ 52 | dnl PHP_ADD_LIBRARY_WITH_PATH($LIBNAME, $GEOHASH_DIR/lib, GEOHASH_SHARED_LIBADD) 53 | dnl AC_DEFINE(HAVE_GEOHASHLIB,1,[ ]) 54 | dnl ],[ 55 | dnl AC_MSG_ERROR([wrong geohash lib version or lib not found]) 56 | dnl ],[ 57 | dnl -L$GEOHASH_DIR/lib -lm 58 | dnl ]) 59 | dnl 60 | dnl PHP_SUBST(GEOHASH_SHARED_LIBADD) 61 | 62 | PHP_NEW_EXTENSION(geohash, geohash.c, $ext_shared) 63 | fi 64 | -------------------------------------------------------------------------------- /php_geohash.h: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2013 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: taogogo love@taogogo.info | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | /* $Id$ */ 20 | 21 | #ifndef PHP_GEOHASH_H 22 | #define PHP_GEOHASH_H 23 | 24 | extern zend_module_entry geohash_module_entry; 25 | #define phpext_geohash_ptr &geohash_module_entry 26 | 27 | #ifdef PHP_WIN32 28 | # define PHP_GEOHASH_API __declspec(dllexport) 29 | #elif defined(__GNUC__) && __GNUC__ >= 4 30 | # define PHP_GEOHASH_API __attribute__ ((visibility("default"))) 31 | #else 32 | # define PHP_GEOHASH_API 33 | #endif 34 | 35 | #ifdef ZTS 36 | #include "TSRM.h" 37 | #endif 38 | 39 | PHP_MINIT_FUNCTION(geohash); 40 | PHP_MSHUTDOWN_FUNCTION(geohash); 41 | PHP_RINIT_FUNCTION(geohash); 42 | PHP_RSHUTDOWN_FUNCTION(geohash); 43 | PHP_MINFO_FUNCTION(geohash); 44 | 45 | PHP_METHOD(Geohash,encode); 46 | PHP_METHOD(Geohash,decode); 47 | 48 | 49 | #ifdef ZTS 50 | #define GEOHASH_G(v) TSRMG(geohash_globals_id, zend_geohash_globals *, v) 51 | #else 52 | #define GEOHASH_G(v) (mpl_globals.v) 53 | #endif 54 | 55 | #endif /* PHP_GEOHASH_H */ 56 | 57 | 58 | /* 59 | * Local variables: 60 | * tab-width: 4 61 | * c-basic-offset: 4 62 | * End: 63 | * vim600: noet sw=4 ts=4 fdm=marker 64 | * vim<600: noet sw=4 ts=4 65 | */ 66 | -------------------------------------------------------------------------------- /geohash_lib.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | typedef struct { 4 | double latitude,longitude; 5 | } coord_struct; 6 | char base32[]="0123456789bcdefghjkmnpqrstuvwxyz"; 7 | int bits[]={16,8,4,2,1}; 8 | const char* geohash_encode(double latitude, double longitude, int precision) { 9 | double lat_interval[]={-90.0,90.0}; 10 | double lon_interval[]={-180.0,180.0}; 11 | int bit,ch,i; 12 | bit=ch=i=0; 13 | int is_even=1; 14 | double mid; 15 | //static char geohash[50]=""; 16 | char *geohash=""; 17 | while(imid){ 21 | ch |=bits[bit]; 22 | lon_interval[0]=mid; 23 | }else{ 24 | lon_interval[1]=mid; 25 | } 26 | }else{ 27 | mid=(lat_interval[0]+lat_interval[1])/2.0; 28 | if(latitude>mid){ 29 | ch |=bits[bit]; 30 | lat_interval[0]=mid; 31 | }else{ 32 | lat_interval[1] = mid; 33 | } 34 | } 35 | is_even=!is_even; 36 | if(bit < 4){ 37 | bit++; 38 | }else{ 39 | i++; 40 | spprintf(&geohash, 0, "%s%c",geohash, base32[ch]); 41 | //zend_printf("%s\n",geohash); 42 | //sprintf(geohash,"%s%c",geohash, base32[ch]); 43 | //zend_printf("%s\n",geohash); 44 | 45 | bit=0; 46 | ch=0; 47 | } 48 | 49 | } 50 | return geohash; 51 | } 52 | 53 | unsigned int str_position(char needle, char *string) { 54 | int pos = -1; 55 | int length = strlen(string); 56 | int i; 57 | for(i = 0; i < length; i++) { 58 | if(needle == string[i]) { 59 | pos = i; 60 | break; 61 | } 62 | 63 | } 64 | 65 | return pos; 66 | } 67 | 68 | coord_struct geohash_decode(char *hash) { 69 | double lat_interval[]={-90.0,90.0}; 70 | double lon_interval[]={-180.0,180.0}; 71 | int hash_length=strlen(hash); 72 | int is_even=1; 73 | int str_postion = 0; 74 | double result[2]; 75 | int i,j; 76 | for ( i = 0; i < hash_length; ++i){ 77 | str_postion=str_position(hash[i], base32); 78 | for ( j = 0; j < 5; ++j){ 79 | if(is_even){ 80 | lon_interval[!(str_postion&bits[j])] = (lon_interval[0]+lon_interval[1])/2.0; 81 | }else{ 82 | lat_interval[!(str_postion&bits[j])] = (lat_interval[0]+lat_interval[1])/2.0; 83 | } 84 | is_even=!is_even; 85 | } 86 | } 87 | coord_struct coord_result; 88 | coord_result.latitude=(lat_interval[0] + lat_interval[1]) / 2; 89 | coord_result.longitude=(lon_interval[0] + lon_interval[1]) / 2; 90 | //zend_printf("%f,%f\n",coord_result.latitude,coord_result.longitude ); 91 | return coord_result; 92 | } 93 | -------------------------------------------------------------------------------- /geohash.c: -------------------------------------------------------------------------------- 1 | /* 2 | +----------------------------------------------------------------------+ 3 | | PHP Version 5 | 4 | +----------------------------------------------------------------------+ 5 | | Copyright (c) 1997-2013 The PHP Group | 6 | +----------------------------------------------------------------------+ 7 | | This source file is subject to version 3.01 of the PHP license, | 8 | | that is bundled with this package in the file LICENSE, and is | 9 | | available through the world-wide-web at the following url: | 10 | | http://www.php.net/license/3_01.txt | 11 | | If you did not receive a copy of the PHP license and are unable to | 12 | | obtain it through the world-wide-web, please send a note to | 13 | | license@php.net so we can mail you a copy immediately. | 14 | +----------------------------------------------------------------------+ 15 | | Author: taogogo love@taogogo.info | 16 | +----------------------------------------------------------------------+ 17 | */ 18 | 19 | /* $Id$ */ 20 | 21 | #ifdef HAVE_CONFIG_H 22 | #include "config.h" 23 | #endif 24 | 25 | #include "php.h" 26 | #include "php_ini.h" 27 | #include "ext/standard/info.h" 28 | #include "php_geohash.h" 29 | //hash map struct 30 | #include "geohash_lib.c" 31 | //struct StrHashTable tbl = {{0},NULL,NULL,simple_strhash,strcmp}; 32 | zval *cfg_value_uhm; 33 | zval *cfg_value; 34 | 35 | /* If you declare any globals in php_geohash.h uncomment this: 36 | ZEND_DECLARE_MODULE_GLOBALS(geohash) 37 | */ 38 | 39 | /* True global resources - no need for thread safety here */ 40 | static int le_geohash; 41 | 42 | /* {{{ geohash_methods[] 43 | */ 44 | const zend_function_entry geohash_methods[] = { 45 | PHP_ME(Geohash, decode, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) 46 | PHP_ME(Geohash, encode, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_STATIC) 47 | PHP_FE_END /* Must be the last line in geohash_methods[] */ 48 | }; 49 | /* }}} */ 50 | 51 | /* {{{ geohash_module_entry 52 | */ 53 | zend_module_entry geohash_module_entry = { 54 | #if ZEND_MODULE_API_NO >= 20010901 55 | STANDARD_MODULE_HEADER, 56 | #endif 57 | "Geohash", 58 | geohash_methods, 59 | PHP_MINIT(geohash), 60 | PHP_MSHUTDOWN(geohash), 61 | PHP_RINIT(geohash), /* Replace with NULL if there's nothing to do at request start */ 62 | PHP_RSHUTDOWN(geohash), /* Replace with NULL if there's nothing to do at request end */ 63 | PHP_MINFO(geohash), 64 | #if ZEND_MODULE_API_NO >= 20010901 65 | "0.1", /* Replace with version number for your extension */ 66 | #endif 67 | STANDARD_MODULE_PROPERTIES 68 | }; 69 | /* }}} */ 70 | 71 | #ifdef COMPILE_DL_GEOHASH 72 | ZEND_GET_MODULE(geohash) 73 | #endif 74 | 75 | zend_class_entry *Geohash_ce; 76 | 77 | /* {{{ PHP_MINIT_FUNCTION 78 | */ 79 | PHP_MINIT_FUNCTION(geohash) 80 | { 81 | REGISTER_STRING_CONSTANT("GEOHASH_VERSION", "0.1", CONST_CS | CONST_PERSISTENT); 82 | //REGISTER_INI_ENTRIES(); 83 | zend_class_entry Geohash_entry; 84 | INIT_CLASS_ENTRY(Geohash_entry, "Geohash", geohash_methods); 85 | Geohash_ce = zend_register_internal_class_ex(&Geohash_entry, NULL, NULL TSRMLS_CC);//注册类 86 | 87 | return SUCCESS; 88 | } 89 | /* }}} */ 90 | 91 | /* {{{ PHP_MSHUTDOWN_FUNCTION 92 | */ 93 | PHP_MSHUTDOWN_FUNCTION(geohash) 94 | { 95 | /* uncomment this line if you have INI entries 96 | UNREGISTER_INI_ENTRIES(); 97 | */ 98 | return SUCCESS; 99 | } 100 | /* }}} */ 101 | 102 | /* Remove if there's nothing to do at request start */ 103 | /* {{{ PHP_RINIT_FUNCTION 104 | */ 105 | PHP_RINIT_FUNCTION(geohash) 106 | { 107 | return SUCCESS; 108 | } 109 | 110 | /* }}} */ 111 | 112 | /* Remove if there's nothing to do at request end */ 113 | /* {{{ PHP_RSHUTDOWN_FUNCTION 114 | */ 115 | PHP_RSHUTDOWN_FUNCTION(geohash) 116 | { 117 | return SUCCESS; 118 | } 119 | /* }}} */ 120 | 121 | /* {{{ PHP_MINFO_FUNCTION 122 | */ 123 | PHP_MINFO_FUNCTION(geohash) 124 | { 125 | php_info_print_table_start(); 126 | php_info_print_table_header(2, "geohash(php geohash extension) support", "enabled"); 127 | //读取常量 128 | zval geohash_version; 129 | if(zend_get_constant("GEOHASH_VERSION", sizeof("GEOHASH_VERSION")-1, &geohash_version TSRMLS_DC)){ 130 | php_info_print_table_row(2, "version", Z_STRVAL(geohash_version)); 131 | } 132 | php_info_print_table_end(); 133 | } 134 | /* }}} */ 135 | 136 | 137 | /* {{{ Geohash::encode 138 | */ 139 | PHP_METHOD(Geohash, decode) { 140 | 141 | char *arg = NULL; 142 | int arg_len; 143 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &arg, &arg_len) == FAILURE) { 144 | return; 145 | } 146 | coord_struct result=geohash_decode(arg); 147 | array_init(return_value); 148 | add_assoc_double(return_value,"latitude",result.latitude); 149 | add_assoc_double(return_value,"longitude",result.longitude); 150 | //zend_printf("gaga"); 151 | } 152 | 153 | /* }}} */ 154 | 155 | /* {{{ Geohash::encode 156 | */ 157 | PHP_METHOD(Geohash, encode) { 158 | 159 | double lat,lon; 160 | long precision=0; 161 | if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "dd|l", &lat, &lon, &precision) == FAILURE) { 162 | return; 163 | } 164 | if(lat>90.0 || lat<-90.0){ 165 | php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Argument #1 range from -90.0 to 90.0"); 166 | return; 167 | } 168 | if(lon>180.0 || lon<-180.0){ 169 | php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Argument #2 range from -180.0 to 180.0"); 170 | return; 171 | } 172 | if(precision!=0){ 173 | if(precision<0){ 174 | php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Argument #3 should be a positive number"); 175 | return; 176 | } 177 | }else{ 178 | precision=12; 179 | } 180 | RETVAL_STRING(geohash_encode(lat,lon,precision),1); 181 | } 182 | 183 | /* }}} */ 184 | 185 | /* The previous line is meant for vim and emacs, so it can correctly fold and 186 | unfold functions in source code. See the corresponding marks just before 187 | function definition, where the functions purpose is also documented. Please 188 | follow this convention for the convenience of others editing your code. 189 | */ 190 | 191 | 192 | /* 193 | * Local variables: 194 | * tab-width: 4 195 | * c-basic-offset: 4 196 | * End: 197 | * vim600: noet sw=4 ts=4 fdm=marker 198 | * vim<600: noet sw=4 ts=4 199 | */ 200 | --------------------------------------------------------------------------------