Code Coverage
 
Lines
Functions and Methods
Classes and Traits
Total
0.00% covered (danger)
0.00%
0 / 108
0.00% covered (danger)
0.00%
0 / 17
CRAP
n/a
0 / 0
zeroBSCRM_textProcess
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
zeroBSCRM_textExpose
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
zeroBSCRM_preDBStr
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
zeroBSCRM_stripExceptLineBreaks
0.00% covered (danger)
0.00%
0 / 5
0.00% covered (danger)
0.00%
0 / 1
2
jpcrm_sanitize_text_field_allow_whitespace
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
2
zeroBSCRM_strings_stripNonAlphaNumeric_dash
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
zeroBSCRM_strings_stripNonNumeric
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
2
jpcrm_is_int
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
42
jpcrm_is_url
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
jpcrm_has_valid_tld
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
jpcrm_url_with_scheme
0.00% covered (danger)
0.00%
0 / 1
0.00% covered (danger)
0.00%
0 / 1
6
zeroBSCRM_validateEmail
0.00% covered (danger)
0.00%
0 / 3
0.00% covered (danger)
0.00%
0 / 1
6
zeroBSCRM_dataIO_postedArrayOfInts
0.00% covered (danger)
0.00%
0 / 6
0.00% covered (danger)
0.00%
0 / 1
6
jpcrm_dataIO_file_path_seems_unsafe
0.00% covered (danger)
0.00%
0 / 7
0.00% covered (danger)
0.00%
0 / 1
20
jpcrm_url_appears_to_match_site
0.00% covered (danger)
0.00%
0 / 4
0.00% covered (danger)
0.00%
0 / 1
6
zeroBSCRM_segments_filterConditions
0.00% covered (danger)
0.00%
0 / 42
0.00% covered (danger)
0.00%
0 / 1
306
zeroBSCRM_segments_unencodeConditions
0.00% covered (danger)
0.00%
0 / 11
0.00% covered (danger)
0.00%
0 / 1
42
1<?php
2/*
3 * Jetpack CRM
4 * https://jetpackcrm.com
5 * V1.20
6 *
7 * Copyright 2020 Automattic
8 *
9 * Date: 01/11/16
10 */
11
12defined( 'ZEROBSCRM_PATH' ) || exit( 0 );
13
14/*
15======================================================
16    Data Processing Functions
17    ====================================================== */
18
19    // Ensures storage and return as UTF8 without slashes
20function zeroBSCRM_textProcess( $string = '' ) {
21    return htmlentities( stripslashes( $string ), ENT_QUOTES, 'UTF-8' );
22}
23function zeroBSCRM_textExpose( $string = '' ) {
24    return html_entity_decode( $string, ENT_QUOTES, 'UTF-8' );
25}
26
27    // hitting this issue
28    // https://core.trac.wordpress.org/ticket/43087
29    // +
30    // https://core.trac.wordpress.org/ticket/32315#comment:43
31    // (pasted emoji's in inputs (log text) would cause a silent wpdb error)
32    // so for now, passing any emoji-ridden text through here:
33function zeroBSCRM_preDBStr( $string = '' ) {
34
35    // encode emoji's - https://core.trac.wordpress.org/ticket/43087
36    return wp_encode_emoji( $string );
37}
38
39    // strips all except <br />
40function zeroBSCRM_stripExceptLineBreaks( $string = '' ) {
41
42    // simplistic switchout. can surely be done more elegantly
43    $brs = array( '<br />', '<br>', '<br/>', '<BR />', '<BR>', '<BR/>' );
44    $str = str_replace( $brs, '###BR###', $string );
45    $str = wp_strip_all_tags( $str, 1 );
46    $str = str_replace( '###BR###', '<br />', $str );
47
48    return $str;
49}
50
51    /*
52     * sanitize_text_field, but allows whitespace through :roll-eyes:
53     * https://developer.wordpress.org/reference/functions/sanitize_text_field/
54     */
55function jpcrm_sanitize_text_field_allow_whitespace( $string = '' ) {
56
57    $string = str_replace( ' ', '**WHITESPACE**', $string );
58    $string = sanitize_text_field( $string );
59    return str_replace( '**WHITESPACE**', ' ', $string );
60}
61
62    // lol https://stackoverflow.com/questions/6063184/how-to-strip-all-characters-except-for-alphanumeric-and-underscore-and-dash
63function zeroBSCRM_strings_stripNonAlphaNumeric_dash( $str = '' ) {
64    return preg_replace( '/[^a-z0-9_\-\s]+/i', '', $str );
65}
66
67    // https://stackoverflow.com/questions/33993461/php-remove-all-non-numeric-characters-from-a-string
68function zeroBSCRM_strings_stripNonNumeric( $str = '' ) {
69    return preg_replace( '/[^0-9]/', '', $str );
70}
71
72/*
73======================================================
74    / Data Processing Functions
75    ====================================================== */
76
77/*
78======================================================
79    Data Validation Functions
80    ====================================================== */
81
82    /*
83     * Taking a variable, this function checks if it could be an int
84     * (returns true if is an int or a string which could be an int)
85    .. with a little help from my friends: https://stackoverflow.com/questions/2012187/how-to-check-that-a-string-is-an-int-but-not-a-double-etc
86     */
87function jpcrm_is_int( $var = false ) {
88
89    // straight check
90    if ( is_int( $var ) ) {
91        return true;
92    }
93
94    // string check
95    if ( is_string( $var ) ) {
96
97        // catch negative
98        if ( str_starts_with( $var, '-' ) ) {
99
100                // use ctype where available
101            if ( function_exists( 'ctype_digit' ) ) {
102                return ctype_digit( substr( $var, 1 ) );
103            } else {
104                return is_numeric( $var );
105            }
106        }
107
108        // use ctype_digit where available to check the string only contains digits
109        if ( function_exists( 'ctype_digit' ) ) {
110            return ctype_digit( $var );
111        } else {
112            return is_numeric( $var );
113        }
114    }
115
116    return false;
117}
118
119/**
120 * Checks if a given string is a URL
121 *
122 * @param string  $s Potential URL string.
123 * @param boolean $do_tld_check use TLD check instead of regex to confirm if it is a valid URL.
124 *
125 * @return boolean
126 */
127function jpcrm_is_url( $s, $do_tld_check = false ) {
128    if ( $do_tld_check ) {
129        return jpcrm_has_valid_tld( $s );
130    }
131    return preg_match( '/^(https?:\/\/|www\.)\w+(\.\w+)*?(\/[^\s]*)?$/', $s );
132}
133
134/**
135 * Checks if host of a given URL is using a whitelisted TLD
136 *
137 * @param string $s URL string.
138 * @param array  $valid_tlds List of approved TLDs.
139 *
140 * @return boolean
141 */
142function jpcrm_has_valid_tld( $s, $valid_tlds = array( '.com', '.net', '.org', '.edu', '.gov', '.co.uk' ) ) {
143    $host = wp_parse_url( jpcrm_url_with_scheme( $s ), PHP_URL_HOST );
144    if ( ! $host ) {
145        return false;
146    }
147    foreach ( $valid_tlds as $tld ) {
148        if ( str_ends_with( $host, $tld ) ) {
149            return true;
150        }
151    }
152    return false;
153}
154
155/**
156 * Adds a scheme to a URL string if it doesn't exist
157 * adapted from https://stackoverflow.com/a/14701491
158 *
159 * @param string $s as a URL string.
160 * @param string $scheme as an optional default scheme.
161 */
162function jpcrm_url_with_scheme( $s, $scheme = 'https' ) {
163    return wp_parse_url( $s, PHP_URL_SCHEME ) === null ? $scheme . '://' . ltrim( $s, '/' ) : $s;
164}
165
166    #} Checks an email addr
167function zeroBSCRM_validateEmail( $emailAddr ) {
168
169    if ( filter_var( $emailAddr, FILTER_VALIDATE_EMAIL ) ) {
170        return true;
171    }
172
173    return false;
174}
175
176function zeroBSCRM_dataIO_postedArrayOfInts( $array = false ) {
177
178    $ret = array();
179    if ( is_array( $array ) ) {
180        $ret = $array;
181    }
182
183    // sanitize
184    $ret = array_map( 'sanitize_text_field', $ret );
185    $ret = array_map( 'intval', $ret );
186
187    return $ret;
188}
189
190    /*
191     * Checks file path doesn't use unsafe/undesirable protocols
192     */
193function jpcrm_dataIO_file_path_seems_unsafe( $file_path_string ) {
194
195    // this one is important enough to be hard typed here #gh-2501
196    if ( str_contains( $file_path_string, 'phar' ) ) {
197        return true;
198    }
199
200    // these we block with their full string (unless we find a reason to open them up)
201    $blocked_protocols = array( 'file', 'http', 'ftp', 'php', 'zlib', 'data', 'glob', 'ssh2', 'rar', 'ogg', 'expect' );
202    foreach ( $blocked_protocols as $protocol ) {
203
204        if ( str_contains( $file_path_string, $protocol . '://' ) ) {
205            return true;
206        }
207    }
208    // this is only as accurate as what we know here and now (!)
209    return false;
210}
211
212/**
213 * A check which does its best to ensure a URI is an url with the same root as existing site
214 *
215 * @param string $url_string A URL string.
216 * @param string $site_path  The site path if applicable.
217 */
218function jpcrm_url_appears_to_match_site( $url_string, $site_path = '' ) {
219    $this_site_url = site_url( $site_path );
220    if ( str_starts_with( $url_string, $this_site_url ) ) {
221        return true;
222    }
223    return false;
224}
225
226/*
227======================================================
228    / Data Validation Functions
229    ====================================================== */
230
231/*
232======================================================
233    Data Validation Functions: Segments
234    ====================================================== */
235
236// filters out segment conditions (From anything passed) which are not 'safe'
237// e.g. on our zeroBSCRM_segments_availableConditions() list
238// ACCEPTS a POST arr
239// $processCharacters dictates whether or not to pass strings through zeroBSCRM_textProcess
240// ... only do so pre-save, not pre "preview" because this html encodes special chars.
241    // note $processCharacters now legacy/defunct.
242function zeroBSCRM_segments_filterConditions( $conditions = array(), $processCharacters = true ) {
243
244    if ( is_array( $conditions ) && count( $conditions ) > 0 ) {
245
246        $approvedConditions = array();
247
248        $availableConditions         = zeroBSCRM_segments_availableConditions();
249        $availableConditionOperators = zeroBSCRM_segments_availableConditionOperators();
250
251        foreach ( $conditions as $c ) {
252
253            // has proper props
254            if ( isset( $c['type'] ) && isset( $c['operator'] ) && isset( $c['value'] ) ) {
255
256                // retrieve val
257                $val = $c['value'];
258                if ( $processCharacters ) {
259                    $val = zeroBSCRM_textProcess( $val ); // only pre-saving
260                }
261                $val = sanitize_text_field( $val );
262
263                // conversions (e.g. date to uts)
264                $val = zeroBSCRM_segments_typeConversions( $val, $c['type'], $c['operator'], 'in' );
265
266                // okay. (passing only expected + validated)
267                $addition = array(
268
269                    'type'     => $c['type'],
270                    'operator' => $c['operator'],
271                    'value'    => $val,
272
273                );
274
275                // ranges:
276
277                    // int/floatval
278                if ( isset( $c['value2'] ) ) {
279
280                    // retrieve val2
281                    $val2 = $c['value2'];
282                    if ( $processCharacters ) {
283                        $val2 = zeroBSCRM_textProcess( $val2 ); // only pre-saving
284                    }
285                    $val2 = sanitize_text_field( $val2 );
286
287                    $addition['value2'] = $val2;
288
289                }
290
291                    // daterange || datetimerange
292                if (
293                            (
294                                $c['operator'] == 'daterange'
295                                ||
296                                $c['operator'] == 'datetimerange'
297                            )
298                            && ! empty( $val )
299                        ) {
300
301                    // hmmm what if peeps use ' - ' in their date formats? This won't work if they do!
302                    if ( str_contains( $val, ' - ' ) ) {
303
304                        $dates = explode( ' - ', $val );
305                        if ( count( $dates ) === 2 ) {
306
307                                $local_date_time = new DateTime( $dates[0], wp_timezone() );
308                                $local_date_time->setTimezone( new DateTimeZone( 'UTC' ) );
309                                $value = $local_date_time->format( 'Y-m-d H:i' );
310
311                                $local_date_time_2 = new DateTime( $dates[1], wp_timezone() );
312                                $local_date_time_2->setTimezone( new DateTimeZone( 'UTC' ) );
313                                $value_2 = $local_date_time_2->format( 'Y-m-d H:i' );
314                                // Set the converted dates to UTC.
315                                $addition['value']  = zeroBSCRM_locale_dateToUTS( $value );
316                                $addition['value2'] = zeroBSCRM_locale_dateToUTS( $value_2 );
317                        }
318                    }
319                }
320
321                // if intrange force it
322                if ( $c['type'] == 'intrange' && ! isset( $addition['value2'] ) ) {
323                    $addition['value2'] = 0;
324                }
325
326                $approvedConditions[] = $addition;
327
328            }
329        }
330
331        return $approvedConditions;
332
333    }
334
335    return array();
336}
337
338// uses zeroBSCRM_textExpose to make query-ready strings,
339// .. because conditions are saved in encoded format, e.g. é = &eacute;
340function zeroBSCRM_segments_unencodeConditions( $conditions = array() ) {
341
342    if ( is_array( $conditions ) && count( $conditions ) > 0 ) {
343
344        $ret = array();
345
346        foreach ( $conditions as $c ) {
347
348            // for now it's just value we're concerned with
349            $nC = $c;
350            if ( isset( $nC['value'] ) ) {
351                $nC['value'] = zeroBSCRM_textExpose( $nC['value'] );
352            }
353            if ( isset( $nC['value2'] ) ) {
354                $nC['value2'] = zeroBSCRM_textExpose( $nC['value2'] );
355            }
356
357            // simple.
358            $ret[] = $nC;
359
360        }
361
362        return $ret;
363
364    }
365
366    return array();
367}
368/*
369======================================================
370    / Data Validation Functions: Segments
371    ====================================================== */