1 /*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Calvin Buckley <calvin@cmpct.info> |
14 +----------------------------------------------------------------------+
15 */
16
17 #ifdef HAVE_CONFIG_H
18 #include "config.h"
19 #endif
20
21 #include "php.h"
22
23 /*
24 * This files contains functions shared between ext/pdo_odbc and ext/odbc,
25 * relating to i.e. connection string quoting rules.
26 *
27 * The declarations are PHPAPI due to being available for shared/static
28 * versions.
29 */
30
31 /**
32 * Determines if a string matches the ODBC quoting rules.
33 *
34 * A valid quoted string begins with a '{', ends with a '}', and has no '}'
35 * inside of the string that aren't repeated (as to be escaped).
36 *
37 * These rules are what .NET also follows.
38 */
php_odbc_connstr_is_quoted(const char * str)39 PHPAPI bool php_odbc_connstr_is_quoted(const char *str)
40 {
41 /* ODBC quotes are curly braces */
42 if (str[0] != '{') {
43 return false;
44 }
45 /* Check for } that aren't doubled up or at the end of the string */
46 size_t length = strlen(str);
47 for (size_t i = 0; i < length; i++) {
48 if (str[i] == '}' && str[i + 1] == '}') {
49 /* Skip over so we don't count it again */
50 i++;
51 } else if (str[i] == '}' && str[i + 1] != '\0') {
52 /* If not at the end, not quoted */
53 return false;
54 }
55 }
56 return true;
57 }
58
59 /**
60 * Determines if a value for a connection string should be quoted.
61 *
62 * The ODBC specification mentions:
63 * "Because of connection string and initialization file grammar, keywords and
64 * and attribute values that contain the characters []{}(),;?*=!@ not enclosed
65 * with braces should be avoided."
66 *
67 * Note that it assumes that the string is *not* already quoted. You should
68 * check beforehand.
69 */
php_odbc_connstr_should_quote(const char * str)70 PHPAPI bool php_odbc_connstr_should_quote(const char *str)
71 {
72 return strpbrk(str, "[]{}(),;?*=!@") != NULL;
73 }
74
75 /**
76 * Estimates the worst-case scenario for a quoted version of a string's size.
77 */
php_odbc_connstr_estimate_quote_length(const char * in_str)78 PHPAPI size_t php_odbc_connstr_estimate_quote_length(const char *in_str)
79 {
80 /* Assume all '}'. Include '{,' '}', and the null terminator too */
81 return (strlen(in_str) * 2) + 3;
82 }
83
84 /**
85 * Quotes a string with ODBC rules.
86 *
87 * Some characters (curly braces, semicolons) are special and must be quoted.
88 * In the case of '}' in a quoted string, they must be escaped SQL style; that
89 * is, repeated.
90 */
php_odbc_connstr_quote(char * out_str,const char * in_str,size_t out_str_size)91 PHPAPI size_t php_odbc_connstr_quote(char *out_str, const char *in_str, size_t out_str_size)
92 {
93 *out_str++ = '{';
94 out_str_size--;
95 while (out_str_size > 2) {
96 if (*in_str == '\0') {
97 break;
98 } else if (*in_str == '}' && out_str_size - 1 > 2) {
99 /* enough room to append */
100 *out_str++ = '}';
101 *out_str++ = *in_str++;
102 out_str_size -= 2;
103 } else if (*in_str == '}') {
104 /* not enough, truncate here */
105 break;
106 } else {
107 *out_str++ = *in_str++;
108 out_str_size--;
109 }
110 }
111 /* append termination */
112 *out_str++ = '}';
113 *out_str++ = '\0';
114 out_str_size -= 2;
115 /* return how many characters were left */
116 return strlen(in_str);
117 }
118