1 /**
2  *     Copyright 2016-2017 Couchbase, Inc.
3  *
4  *   Licensed under the Apache License, Version 2.0 (the "License");
5  *   you may not use this file except in compliance with the License.
6  *   You may obtain a copy of the License at
7  *
8  *       http://www.apache.org/licenses/LICENSE-2.0
9  *
10  *   Unless required by applicable law or agreed to in writing, software
11  *   distributed under the License is distributed on an "AS IS" BASIS,
12  *   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  *   See the License for the specific language governing permissions and
14  *   limitations under the License.
15  */
16 
17 #include "couchbase.h"
18 #include <Zend/zend_alloc.h>
19 
20 #define LOGARGS(lvl) LCB_LOG_##lvl, NULL, "pcbc/mutation_token", __FILE__, __LINE__
21 
22 zend_class_entry *pcbc_mutation_token_ce;
23 
24 /* {{{ proto void MutationToken::__construct() Should not be called directly */
PHP_METHOD(MutationToken,__construct)25 PHP_METHOD(MutationToken, __construct)
26 {
27     throw_pcbc_exception("Accessing private constructor.", LCB_EINVAL);
28 }
29 /* }}} */
30 
31 /* {{{ proto \Couchbase\MutationToken MutationToken::from(string $bucketName, int $vbucketID, string $vbucketUUID,
32                                                           string $sequeceNumber) */
PHP_METHOD(MutationToken,from)33 PHP_METHOD(MutationToken, from)
34 {
35     long vbid = 0;
36     char *bucket = NULL, *vbuuid = NULL, *seqno = NULL;
37     pcbc_str_arg_size bucket_len = 0, vbuuid_len = 0, seqno_len = 0;
38     int rv;
39 
40     rv = zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "slss", &bucket, &bucket_len, &vbid, &vbuuid, &vbuuid_len,
41                                &seqno, &seqno_len);
42     if (rv == FAILURE) {
43         RETURN_NULL();
44     }
45 
46     pcbc_mutation_token_init_php(return_value, bucket, bucket_len, vbid, vbuuid, vbuuid_len, seqno,
47                                  seqno_len TSRMLS_CC);
48 } /* }}} */
49 
50 /* {{{ proto string MutationToken::bucketName() */
PHP_METHOD(MutationToken,bucketName)51 PHP_METHOD(MutationToken, bucketName)
52 {
53     pcbc_mutation_token_t *obj;
54     int rv;
55 
56     rv = zend_parse_parameters_none();
57     if (rv == FAILURE) {
58         RETURN_NULL();
59     }
60     obj = Z_MUTATION_TOKEN_OBJ_P(getThis());
61 
62 #if PHP_VERSION_ID >= 70000
63     ZVAL_STRING(return_value, obj->bucket);
64 #else
65     ZVAL_STRING(return_value, obj->bucket, 1);
66 #endif
67 } /* }}} */
68 
69 /* {{{ proto int MutationToken::vbucketId() */
PHP_METHOD(MutationToken,vbucketId)70 PHP_METHOD(MutationToken, vbucketId)
71 {
72     pcbc_mutation_token_t *obj;
73     int rv;
74 
75     rv = zend_parse_parameters_none();
76     if (rv == FAILURE) {
77         RETURN_NULL();
78     }
79     obj = Z_MUTATION_TOKEN_OBJ_P(getThis());
80 
81     RETURN_LONG(PCBC_MUTATION_TOKEN_VB(obj));
82 } /* }}} */
83 
84 /* {{{ proto int MutationToken::vbucketUuid() */
PHP_METHOD(MutationToken,vbucketUuid)85 PHP_METHOD(MutationToken, vbucketUuid)
86 {
87     pcbc_mutation_token_t *obj;
88     int rv;
89     char *str;
90 
91     rv = zend_parse_parameters_none();
92     if (rv == FAILURE) {
93         RETURN_NULL();
94     }
95     obj = Z_MUTATION_TOKEN_OBJ_P(getThis());
96 
97     str = pcbc_base36_encode_str(PCBC_MUTATION_TOKEN_ID(obj));
98 #if PHP_VERSION_ID >= 70000
99     ZVAL_STRING(return_value, str);
100     efree(str);
101 #else
102     ZVAL_STRING(return_value, str, 0);
103 #endif
104 } /* }}} */
105 
106 /* {{{ proto int MutationToken::sequenceNumber() */
PHP_METHOD(MutationToken,sequenceNumber)107 PHP_METHOD(MutationToken, sequenceNumber)
108 {
109     pcbc_mutation_token_t *obj;
110     int rv;
111     char *str;
112 
113     rv = zend_parse_parameters_none();
114     if (rv == FAILURE) {
115         RETURN_NULL();
116     }
117     obj = Z_MUTATION_TOKEN_OBJ_P(getThis());
118 
119     str = pcbc_base36_encode_str(PCBC_MUTATION_TOKEN_SEQ(obj));
120 #if PHP_VERSION_ID >= 70000
121     ZVAL_STRING(return_value, str);
122     efree(str);
123 #else
124     ZVAL_STRING(return_value, str, 0);
125 #endif
126 } /* }}} */
127 
128 ZEND_BEGIN_ARG_INFO_EX(ai_MutationToken_none, 0, 0, 0)
129 ZEND_END_ARG_INFO()
130 
131 ZEND_BEGIN_ARG_INFO_EX(ai_MutationToken_from, 0, 0, 4)
132 ZEND_ARG_INFO(0, bucketName)
133 ZEND_ARG_INFO(0, vbucketId)
134 ZEND_ARG_INFO(0, vbucketUuid)
135 ZEND_ARG_INFO(0, sequenceNumber)
136 ZEND_END_ARG_INFO()
137 
138 // clang-format off
139 zend_function_entry mutation_token_methods[] = {
140     PHP_ME(MutationToken, __construct, ai_MutationToken_none, ZEND_ACC_PRIVATE | ZEND_ACC_FINAL | ZEND_ACC_CTOR)
141     PHP_ME(MutationToken, from, ai_MutationToken_from, ZEND_ACC_STATIC | ZEND_ACC_PUBLIC)
142     PHP_ME(MutationToken, bucketName, ai_MutationToken_none, ZEND_ACC_PUBLIC)
143     PHP_ME(MutationToken, vbucketId, ai_MutationToken_none, ZEND_ACC_PUBLIC)
144     PHP_ME(MutationToken, vbucketUuid, ai_MutationToken_none, ZEND_ACC_PUBLIC)
145     PHP_ME(MutationToken, sequenceNumber, ai_MutationToken_none, ZEND_ACC_PUBLIC)
146     PHP_FE_END
147 };
148 // clang-format on
149 
150 zend_object_handlers pcbc_mutation_token_handlers;
151 
pcbc_mutation_token_init(zval * return_value,const char * bucket,const lcb_MUTATION_TOKEN * mt TSRMLS_DC)152 void pcbc_mutation_token_init(zval *return_value, const char *bucket, const lcb_MUTATION_TOKEN *mt TSRMLS_DC)
153 {
154     pcbc_mutation_token_t *token;
155 
156     object_init_ex(return_value, pcbc_mutation_token_ce);
157     token = Z_MUTATION_TOKEN_OBJ_P(return_value);
158     token->bucket = estrdup(bucket);
159     token->mt = *mt;
160 }
161 
pcbc_mutation_token_init_php(zval * return_value,char * bucket,int bucket_len,long vbid,char * vbuuid,int vbuuid_len,char * seqno,int seqno_len TSRMLS_DC)162 void pcbc_mutation_token_init_php(zval *return_value, char *bucket, int bucket_len, long vbid, char *vbuuid,
163                                   int vbuuid_len, char *seqno, int seqno_len TSRMLS_DC)
164 {
165     lcb_MUTATION_TOKEN mt;
166     LCB_MUTATION_TOKEN_VB(&mt) = (lcb_U16)vbid;
167     LCB_MUTATION_TOKEN_ID(&mt) = pcbc_base36_decode_str(vbuuid, vbuuid_len);
168     LCB_MUTATION_TOKEN_SEQ(&mt) = pcbc_base36_decode_str(seqno, seqno_len);
169     pcbc_mutation_token_init(return_value, bucket, &mt TSRMLS_CC);
170 }
171 
mutation_token_free_object(pcbc_free_object_arg * object TSRMLS_DC)172 static void mutation_token_free_object(pcbc_free_object_arg *object TSRMLS_DC) /* {{{ */
173 {
174     pcbc_mutation_token_t *obj = Z_MUTATION_TOKEN_OBJ(object);
175 
176     efree(obj->bucket);
177 
178     zend_object_std_dtor(&obj->std TSRMLS_CC);
179 #if PHP_VERSION_ID < 70000
180     efree(obj);
181 #endif
182 } /* }}} */
183 
mutation_token_create_object(zend_class_entry * class_type TSRMLS_DC)184 static pcbc_create_object_retval mutation_token_create_object(zend_class_entry *class_type TSRMLS_DC)
185 {
186     pcbc_mutation_token_t *obj = NULL;
187 
188     obj = PCBC_ALLOC_OBJECT_T(pcbc_mutation_token_t, class_type);
189 
190     zend_object_std_init(&obj->std, class_type TSRMLS_CC);
191     object_properties_init(&obj->std, class_type);
192 
193 #if PHP_VERSION_ID >= 70000
194     obj->std.handlers = &pcbc_mutation_token_handlers;
195     return &obj->std;
196 #else
197     {
198         zend_object_value ret;
199         ret.handle = zend_objects_store_put(obj, (zend_objects_store_dtor_t)zend_objects_destroy_object,
200                                             mutation_token_free_object, NULL TSRMLS_CC);
201         ret.handlers = &pcbc_mutation_token_handlers;
202         return ret;
203     }
204 #endif
205 }
206 
mutation_token_get_debug_info(zval * object,int * is_temp TSRMLS_DC)207 static HashTable *mutation_token_get_debug_info(zval *object, int *is_temp TSRMLS_DC) /* {{{ */
208 {
209     pcbc_mutation_token_t *obj = NULL;
210 #if PHP_VERSION_ID >= 70000
211     zval retval;
212 #else
213     zval retval = zval_used_for_init;
214 #endif
215     char *num36;
216 
217     *is_temp = 1;
218     obj = Z_MUTATION_TOKEN_OBJ_P(object);
219 
220     array_init(&retval);
221     ADD_ASSOC_STRING(&retval, "bucket", obj->bucket);
222     ADD_ASSOC_LONG_EX(&retval, "vbucketId", PCBC_MUTATION_TOKEN_VB(obj));
223     num36 = pcbc_base36_encode_str(PCBC_MUTATION_TOKEN_ID(obj));
224     ADD_ASSOC_STRING(&retval, "vbucketUuid", num36);
225     efree(num36);
226     num36 = pcbc_base36_encode_str(PCBC_MUTATION_TOKEN_SEQ(obj));
227     ADD_ASSOC_STRING(&retval, "sequenceNumber", num36);
228     efree(num36);
229 
230     return Z_ARRVAL(retval);
231 } /* }}} */
232 
PHP_MINIT_FUNCTION(MutationToken)233 PHP_MINIT_FUNCTION(MutationToken)
234 {
235     zend_class_entry ce;
236 
237     INIT_NS_CLASS_ENTRY(ce, "Couchbase", "MutationToken", mutation_token_methods);
238     pcbc_mutation_token_ce = zend_register_internal_class(&ce TSRMLS_CC);
239     pcbc_mutation_token_ce->create_object = mutation_token_create_object;
240     PCBC_CE_DISABLE_SERIALIZATION(pcbc_mutation_token_ce);
241 
242     memcpy(&pcbc_mutation_token_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers));
243     pcbc_mutation_token_handlers.get_debug_info = mutation_token_get_debug_info;
244 #if PHP_VERSION_ID >= 70000
245     pcbc_mutation_token_handlers.free_obj = mutation_token_free_object;
246     pcbc_mutation_token_handlers.offset = XtOffsetOf(pcbc_mutation_token_t, std);
247 #endif
248 
249     zend_register_class_alias("\\CouchbaseMutationToken", pcbc_mutation_token_ce);
250     return SUCCESS;
251 }
252