2121#endif
2222
2323#include "php.h"
24+ #include "Zend/zend_exceptions.h"
2425
2526#include "curl_private.h"
2627
2728#include <curl/curl.h>
2829
2930#define SAVE_CURLSH_ERROR (__handle , __err ) (__handle)->err.no = (int) __err;
3031
32+ /**
33+ * Free a persistent curl share handle.
34+ */
3135void curl_share_free_persistent (zval * data )
3236{
3337 CURLSH * handle = Z_PTR_P (data );
@@ -39,84 +43,104 @@ void curl_share_free_persistent(zval *data)
3943 curl_share_cleanup (handle );
4044}
4145
42- /* {{{ Initialize a persistent curl share handle */
43- PHP_FUNCTION (curl_share_init_persistent )
46+ /**
47+ * Initialize a share curl handle, optionally with share options and a persistent ID.
48+ */
49+ PHP_FUNCTION (curl_share_init )
4450{
45- zend_string * id ;
46-
47- zval * persisted ;
51+ zval * share_opts = NULL , * entry ;
52+ zend_string * persistent_id ;
4853
4954 php_curlsh * sh ;
5055
51- zval * arr , * entry ;
5256 CURLSHcode error ;
5357
54- ZEND_PARSE_PARAMETERS_START (2 , 2 )
55- Z_PARAM_STR_EX (id , 1 , 0 )
56- Z_PARAM_ARRAY (arr )
58+ ZEND_PARSE_PARAMETERS_START (0 , 2 )
59+ Z_PARAM_OPTIONAL
60+ Z_PARAM_ARRAY (share_opts )
61+ Z_PARAM_STR_OR_NULL (persistent_id )
5762 ZEND_PARSE_PARAMETERS_END ();
5863
5964 object_init_ex (return_value , curl_share_ce );
6065 sh = Z_CURL_SHARE_P (return_value );
6166
62- if ((persisted = zend_hash_find (& CURL_G (persistent_share_handles ), id )) != NULL ) {
63- sh -> share = Z_PTR_P (persisted );
64- sh -> persistent = 1 ;
65- } else {
66- sh -> share = curl_share_init ();
67+ if (persistent_id ) {
68+ zval * persisted = zend_hash_find (& CURL_G (persistent_share_handles ), persistent_id );
69+
70+ if (persisted ) {
71+ sh -> share = Z_PTR_P (persisted );
72+ sh -> persistent_id = zend_string_copy (persistent_id );
73+
74+ return ;
75+ }
76+ }
77+
78+ // The user did not provide a persistent share ID, or we could not find an existing share handle, so we'll have to
79+ // create one.
80+ sh -> share = curl_share_init ();
6781
68- ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P (arr ), entry ) {
82+ if (share_opts ) {
83+ ZEND_HASH_FOREACH_VAL (Z_ARRVAL_P (share_opts ), entry ) {
6984 ZVAL_DEREF (entry );
7085
71- error = curl_share_setopt (sh -> share , CURLSHOPT_SHARE , zval_get_long (entry ));
86+ error = curl_share_setopt (sh -> share , CURLSHOPT_SHARE , zval_get_long_ex (entry , true ));
7287
7388 if (error != CURLSHE_OK ) {
74- php_error_docref (NULL , E_WARNING , "could not construct persistent curl share: %s" , curl_share_strerror (error ));
89+ zend_throw_exception_ex (
90+ NULL ,
91+ 0 ,
92+ "Could not construct cURL share handle: %s" ,
93+ curl_share_strerror (error )
94+ );
7595
7696 goto error ;
7797 }
7898 } ZEND_HASH_FOREACH_END ();
99+ }
79100
101+ if (persistent_id ) {
80102 // It's important not to mark this as persistent until *after* we've successfully set all of the share options,
81103 // as otherwise the curl_share_free_obj in the error handler won't free the CURLSH.
82- sh -> persistent = 1 ;
83-
84- zend_hash_str_add_new_ptr (& CURL_G (persistent_share_handles ), ZSTR_VAL (id ), ZSTR_LEN (id ), sh -> share );
104+ sh -> persistent_id = zend_string_copy (persistent_id );
105+
106+ // We use the zend_hash_str form here, since we want to ensure it allocates a new persistent string, instead of
107+ // using the request-bound persistent_id.
108+ zend_hash_str_add_new_ptr (
109+ & CURL_G (persistent_share_handles ),
110+ ZSTR_VAL (persistent_id ),
111+ ZSTR_LEN (persistent_id ),
112+ sh -> share
113+ );
85114 }
86115
87116 return ;
88117
89118 error :
90119 zval_ptr_dtor (return_value );
91120
92- RETURN_FALSE ;
121+ RETURN_THROWS () ;
93122}
94- /* }}} */
95-
96- /* {{{ Initialize a share curl handle */
97- PHP_FUNCTION (curl_share_init )
98- {
99- php_curlsh * sh ;
100-
101- ZEND_PARSE_PARAMETERS_NONE ();
102123
103- object_init_ex (return_value , curl_share_ce );
104- sh = Z_CURL_SHARE_P (return_value );
105-
106- sh -> share = curl_share_init ();
107- }
108- /* }}} */
109-
110- /* {{{ Close a set of cURL handles */
124+ /**
125+ * Close a persistent curl share handle. NOP for non-persistent share handles.
126+ */
111127PHP_FUNCTION (curl_share_close )
112128{
113129 zval * z_sh ;
114130
131+ php_curlsh * sh ;
132+
115133 ZEND_PARSE_PARAMETERS_START (1 ,1 )
116134 Z_PARAM_OBJECT_OF_CLASS (z_sh , curl_share_ce )
117135 ZEND_PARSE_PARAMETERS_END ();
136+
137+ sh = Z_CURL_SHARE_P (z_sh );
138+
139+ if (sh -> persistent_id ) {
140+ // Deleting the share from the hash table will trigger curl_share_free_persistent, so no need to call it here.
141+ zend_hash_del (& CURL_G (persistent_share_handles ), sh -> persistent_id );
142+ }
118143}
119- /* }}} */
120144
121145static bool _php_curl_share_setopt (php_curlsh * sh , zend_long option , zval * zvalue , zval * return_value ) /* {{{ */
122146{
@@ -138,9 +162,10 @@ static bool _php_curl_share_setopt(php_curlsh *sh, zend_long option, zval *zvalu
138162
139163 return error == CURLSHE_OK ;
140164}
141- /* }}} */
142165
143- /* {{{ Set an option for a cURL transfer */
166+ /**
167+ * Set an option for a cURL transfer.
168+ */
144169PHP_FUNCTION (curl_share_setopt )
145170{
146171 zval * z_sh , * zvalue ;
@@ -161,9 +186,10 @@ PHP_FUNCTION(curl_share_setopt)
161186 RETURN_FALSE ;
162187 }
163188}
164- /* }}} */
165189
166- /* {{{ Return an integer containing the last share curl error number */
190+ /**
191+ * Return an integer containing the last share curl error number.
192+ */
167193PHP_FUNCTION (curl_share_errno )
168194{
169195 zval * z_sh ;
@@ -177,10 +203,11 @@ PHP_FUNCTION(curl_share_errno)
177203
178204 RETURN_LONG (sh -> err .no );
179205}
180- /* }}} */
181206
182207
183- /* {{{ return string describing error code */
208+ /**
209+ * Return a string describing the error code.
210+ */
184211PHP_FUNCTION (curl_share_strerror )
185212{
186213 zend_long code ;
@@ -197,7 +224,6 @@ PHP_FUNCTION(curl_share_strerror)
197224 RETURN_NULL ();
198225 }
199226}
200- /* }}} */
201227
202228/* CurlShareHandle class */
203229
@@ -219,8 +245,10 @@ void curl_share_free_obj(zend_object *object)
219245{
220246 php_curlsh * sh = curl_share_from_obj (object );
221247
222- if (!sh -> persistent ) {
248+ if (!sh -> persistent_id ) {
223249 curl_share_cleanup (sh -> share );
250+ } else {
251+ zend_string_release (sh -> persistent_id );
224252 }
225253
226254 zend_object_std_dtor (& sh -> std );
0 commit comments