PluginProbe
Flexmls® IDX Plugin / 3.8.2
Flexmls® IDX Plugin v3.8.2
4.0.1 4.0.0 3.18.2 trunk 0.9.0 0.9.1 0.9.2 0.9.3 0.9.4 0.9.5 0.9.6 2.0 2.1 2.2 2.3 2.3.1 2.3.2 2.3.3 2.4 2.4.1 2.4.2 3.0.0 3.0.1 3.0.10 3.0.11 All 157 releases
flexmls-idx / SparkAPI / Core.php

Core.php in Flexmls® IDX Plugin 3.8.2, at SparkAPI/Core.php

330 lines 11.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 namespace SparkAPI;
3
4 defined( 'ABSPATH' ) or die( 'This plugin requires WordPress' );
5
6 class Core {
7
8 protected $api_base;
9 protected $api_headers;
10 protected $api_version;
11 protected $plugin_version;
12
13 function __construct(){
14 $this->api_base = FMC_API_BASE;
15 $this->api_version = FMC_API_VERSION;
16 $this->plugin_version = FMC_PLUGIN_VERSION;
17 $this->api_headers = array(
18 'Accept-Encoding' => 'gzip,deflate',
19 'Content-Type' => 'application/json',
20 'User-Agent' => 'FlexMLS WordPress Plugin/' . $this->api_version,
21 'X-SparkApi-User-Agent' => 'flexmls-WordPress-Plugin/' . $this->plugin_version
22 );
23 }
24
25 function admin_notices_api_connection_error(){
26 echo ' <div class="notice notice-error">
27 <p>There was an error connecting to the FlexMLS&reg; IDX API. Please check your credentials and try again. If your credentials are correct and you continue to see this error message, please <a href="' . admin_url( 'admin.php?page=fmc_admin_settings&tab=support' ) . '">contact support</a>.</p>
28 </div>';
29 }
30
31 function clear_cache( $force = false ){
32 global $wpdb;
33 /*----------------------------------------------------------------------
34 VERSION 3.5.9
35 New caching system implemented using only WordPress transients so we
36 need to delete all old options from previous versions that were
37 clogging up the database. This first query deletes all old options
38 using the fmc_ transient & caching system. We delete these 250 at
39 a time to try not to crash agent servers.
40 ----------------------------------------------------------------------*/
41 $delete_query = "DELETE FROM $wpdb->options WHERE option_name LIKE %s OR option_name LIKE %s LIMIT 250";
42 $wpdb->query( $wpdb->prepare(
43 $delete_query,
44 '_transient_fmc%',
45 '_transient_timeout_fmc%'
46 ) );
47
48 if( true === $force ){
49 /*----------------------------------------------------------------------
50 The user has requested that ALL FlexMLS caches be purged so
51 we will bulk delete all newly created FlexMLS caches
52 ----------------------------------------------------------------------*/
53 $wpdb->query( $wpdb->prepare(
54 $delete_query,
55 '_transient_flexmls_query_%',
56 '_transient_timeout_flexmls_query_%'
57 ) );
58 delete_option( 'fmc_db_cache_key' );
59 } else {
60 /*----------------------------------------------------------------------
61 Just delete expired FlexMLS transients but leave current ones
62 in tact. This is just regular clean-up, not a forced cache clear.
63 ----------------------------------------------------------------------*/
64 $time = time();
65 $sql = "DELETE a, b FROM $wpdb->options a, $wpdb->options b
66 WHERE a.option_name LIKE %s
67 AND a.option_name NOT LIKE %s
68 AND b.option_name = CONCAT( '_transient_timeout_', SUBSTRING( a.option_name, 12 ) )
69 AND b.option_value < %d";
70 $wpdb->query( $wpdb->prepare(
71 $sql, $wpdb->esc_like( '_transient_flexmls_query_' ) . '%',
72 $wpdb->esc_like( '_transient_timeout_flexmls_query_' ) . '%',
73 $time
74 ) );
75 }
76 delete_transient( 'flexmls_auth_token' );
77 $this->generate_auth_token();
78 return true;
79 }
80
81 function generate_auth_token( $retry = true ){
82 global $auth_token_failures;
83 if( false === ( $auth_token = get_transient( 'flexmls_auth_token' ) ) && $auth_token_failures < 2 ){
84 $options = get_option( 'fmc_settings' );
85 if( !isset( $options[ 'api_key' ] ) || empty( $options[ 'api_key' ] ) || !isset( $options[ 'api_secret' ] ) || empty( $options[ 'api_secret' ] ) ){
86 return false;
87 }
88 $security_string = md5( $options[ 'api_secret' ] . 'ApiKey' . $options[ 'api_key' ] );
89 $params = array(
90 'ApiKey' => $options[ 'api_key' ],
91 'ApiSig' => $security_string
92 );
93 $query = build_query( $params );
94 $url = 'https://' . $this->api_base . '/' . $this->api_version . '/session?' . build_query( $params );
95 $args = array(
96 'headers' => $this->api_headers
97 );
98 $response = wp_remote_post( $url, $args );
99 if( is_wp_error( $response ) ){
100 $auth_token_failures++;
101 if( false === $retry ){
102 add_action( 'admin_notices', array( $this, 'admin_notices_api_connection_error' ) );
103 return false;
104 } else {
105 $auth_token = $this->generate_auth_token( false );
106 }
107 } else {
108 $json = json_decode( wp_remote_retrieve_body( $response ), true );
109 if( array_key_exists( 'D', $json ) && true == $json[ 'D' ][ 'Success' ] ){
110 set_transient( 'flexmls_auth_token', $json, 15 * MINUTE_IN_SECONDS );
111 $auth_token = $json;
112 $auth_token_failures = 0;
113 } else {
114 $auth_token_failures++;
115 }
116 }
117 }
118 return $auth_token;
119 }
120
121 function get_first_result( $response ){
122 if( true == $response[ 'success' ] ){
123 if( count( $response[ 'results' ] ) ){
124 return $response[ 'results' ][ 0 ];
125 } else {
126 return null;
127 }
128 }
129 return false;
130 }
131
132 function get_all_results( $response = array() ){
133 if( isset( $response[ 'success' ] ) && $response[ 'success' ] ){
134 return $response[ 'results' ];
135 }
136 return false;
137 }
138
139 // This function is used for calls done from inside this instantiated class
140 function get_from_api( $method, $service, $cache_time = 0, $params = array(), $post_data = null, $a_retry = false ){
141 $json = $this->make_api_call( $method, $service, $cache_time, $params, $post_data, $a_retry );
142 $return = array();
143
144 if( array_key_exists( 'D', $json ) ){
145 if( array_key_exists( 'Code', $json[ 'D' ] ) ){
146 $this->last_error_code = $json[ 'D' ][ 'Code' ];
147 $return[ 'api_code' ] = $json[ 'D' ][ 'Code' ];
148 }
149 if( array_key_exists( 'Message', $json[ 'D' ] ) ){
150 $this->last_error_mess = $json[ 'D' ][ 'Message' ];
151 $return[ 'api_message' ] = $json[ 'D' ][ 'Message' ];
152 }
153 if( array_key_exists( 'Pagination', $json[ 'D' ] ) ){
154 $this->last_count = $json[ 'D' ][ 'Pagination' ][ 'TotalRows' ];
155 $this->page_size = $json[ 'D' ][ 'Pagination' ][ 'PageSize' ];
156 $this->total_pages = $json[ 'D' ][ 'Pagination' ][ 'TotalPages' ];
157 $this->current_page = $json[ 'D' ][ 'Pagination' ][ 'CurrentPage' ];
158 } else {
159 $this->last_count = null;
160 $this->page_size = null;
161 $this->total_pages = null;
162 $this->current_page = null;
163 }
164 if( true == $json[ 'D' ][ 'Success' ] ){
165 $return[ 'success' ] = true;
166 $return[ 'results' ] = $json[ 'D' ][ 'Results' ];
167 } else {
168 $return[ 'success' ] = false;
169 }
170 }
171 return $return;
172 }
173
174 function is_not_blank_or_restricted( $val ){
175 // Need to find back references and delete them.
176 // This temporary placeholder is so nothing breaks in the interim.
177 // It should be removed and references should be to the Formatter class.
178 return \FlexMLS\Admin\Formatter::is_not_blank_or_restricted( $val );
179 }
180
181 function make_api_call( $method, $service, $cache_time = 0, $params = array(), $post_data = null, $a_retry = false ){
182 //\FlexMLS_IDX::write_log( debug_backtrace() );
183 if( !$this->generate_auth_token() ){
184 // $this->get_from_api expects an array. Send one that indicates
185 // we're not connected to the API.
186 return array( 'D' => array( 'Success' => false ) );
187 }
188 $seconds_to_cache = $this->parse_cache_time( $cache_time );
189
190 $method = sanitize_text_field( $method );
191
192 $request = array(
193 'cache_duration' => $seconds_to_cache,
194 'method' => $method,
195 'params' => $params,
196 'post_data' => $post_data,
197 'service' => $service
198 );
199
200 $request = $this->sign_request( $request );
201
202 $transient_name = 'flexmls_query_' . $request[ 'transient_name' ];
203
204 $is_auth_request = ( 'session' == $request[ 'service' ] ? true : false );
205
206 if( $is_auth_request ){
207 return $this->generate_auth_token();
208 }
209
210 $return = array();
211
212 if( false === ( $json = get_transient( $transient_name ) ) ){
213 $url = 'https://' . $this->api_base . '/' . $this->api_version . '/' . $service . '?' . $request[ 'query_string' ];
214 $json = array();
215 $args = array(
216 'method' => $method,
217 'headers' => $this->api_headers,
218 'body' => $post_data
219 );
220 $response = wp_remote_request( $url, $args );
221
222 $return = array(
223 'http_code' => wp_remote_retrieve_response_code( $response )
224 );
225
226 if( is_wp_error( $response ) ){
227 add_action( 'admin_notices', array( $this, 'admin_notices_api_connection_error' ) );
228 return $return;
229 }
230 $json = json_decode( wp_remote_retrieve_body( $response ), true );
231 if( !is_array( $json ) ){
232 // The response wasn't JSON as expected so bail out with the original, unparsed body
233 $return[ 'body' ] = $json;
234 return $return;
235 }
236 if( array_key_exists( 'D', $json ) ){
237 if( true == $json[ 'D' ][ 'Success' ] && 'GET' == strtoupper( $method ) ){
238 set_transient( 'flexmls_query_' . $request[ 'transient_name' ], $json, $seconds_to_cache );
239 } elseif( isset( $json[ 'D' ][ 'Code' ] ) && 1020 == $json[ 'D' ][ 'Code' ] ){
240 delete_transient( 'flexmls_auth_token' );
241 if( $this->generate_auth_token() ){
242 $json = $this->make_api_call( $method, $service, $cache_time = 0, $params = array(), $post_data = null, $a_retry = false );
243 }
244 }
245 }
246 }
247 return $json;
248 }
249
250 function make_sendable_body( $data ){
251 return json_encode( array( 'D' => $data ) );
252 }
253
254 function parse_cache_time( $time_value = 0 ){
255 // Need to find back references and delete them.
256 // This temporary placeholder is so nothing breaks in the interim.
257 // It should be removed and references should be to the Formatter class.
258 return \FlexMLS\Admin\Formatter::parse_cache_time( $time_value );
259 }
260
261 function parse_location_search_string( $location ){
262 // Need to find back references and delete them.
263 // This temporary placeholder is so nothing breaks in the interim.
264 // It should be removed and references should be to the Formatter class.
265 return \FlexMLS\Admin\Formatter::parse_location_search_string( $location );
266 }
267
268 function return_all_results( $response = array() ){
269 return $this->get_all_results( $response );
270 }
271
272 function sign_request( $request ){
273 $options = get_option( 'fmc_settings' );
274 $security_string = $options[ 'api_secret' ] . 'ApiKey' . $options[ 'api_key' ];
275
276 $request[ 'cacheable_query_string' ] = build_query( $request[ 'params' ] );
277 $params = $request[ 'params' ];
278
279 $post_body = '';
280 if( 'POST' == $request[ 'method' ] && !empty( $request[ 'post_data' ] ) ){
281 // the request is to post some JSON data back to the API (like adding a contact)
282 $post_body = $request[ 'post_data' ];
283 }
284
285 $is_auth_request = ( 'session' == $request[ 'service' ] ? true : false );
286
287 if( $is_auth_request ){
288 $params[ 'ApiKey' ] = $options[ 'api_key' ];
289 } else {
290 $params[ 'AuthToken' ] = '';
291 $auth_token = get_transient( 'flexmls_auth_token' );
292 if( $auth_token ){
293 $params[ 'AuthToken' ] = $auth_token[ 'D' ][ 'Results' ][ 0 ][ 'AuthToken' ];
294 }
295
296 $security_string .= 'ServicePath' . rawurldecode( '/' . $this->api_version . '/' . $request[ 'service' ] );
297
298 ksort( $params );
299
300 $params_encoded = array();
301
302 foreach( $params as $key => $value ){
303 $security_string .= $key . $value;
304 $params_encoded[ $key ] = urlencode( $value );
305 }
306 }
307 if( !empty( $post_body ) ){
308 // add the post data to the end of the security string if it exists
309 $security_string .= $post_body;
310 }
311
312 $params_encoded[ 'ApiSig' ] = md5( $security_string );
313
314 $request[ 'params' ] = $params_encoded;
315
316 $request[ 'query_string' ] = build_query( $params_encoded );
317
318 if( isset( $params_encoded[ 'AuthToken' ] ) ){
319 unset( $params_encoded[ 'AuthToken' ] );
320 }
321 unset( $params_encoded[ 'ApiSig' ] );
322
323 $params_encoded[ $request[ 'method' ] ] = $request[ 'service' ];
324
325 $request[ 'transient_name' ] = sha1( build_query( $params_encoded ) );
326
327 return $request;
328 }
329 }
330