Coverage Report

Created: 2025-06-13 06:43

/src/php-src/main/php_odbc_utils.c
Line
Count
Source (jump to first uncovered line)
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
 */
39
PHPAPI bool php_odbc_connstr_is_quoted(const char *str)
40
0
{
41
  /* ODBC quotes are curly braces */
42
0
  if (str[0] != '{') {
43
0
    return false;
44
0
  }
45
  /* Check for } that aren't doubled up or at the end of the string */
46
0
  size_t length = strlen(str);
47
0
  for (size_t i = 0; i < length; i++) {
48
0
    if (str[i] == '}' && str[i + 1] == '}') {
49
      /* Skip over so we don't count it again */
50
0
      i++;
51
0
    } else if (str[i] == '}' && str[i + 1] != '\0') {
52
      /* If not at the end, not quoted */
53
0
      return false;
54
0
    }
55
0
  }
56
0
  return true;
57
0
}
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
 * 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
 */
70
PHPAPI bool php_odbc_connstr_should_quote(const char *str)
71
0
{
72
0
  return strpbrk(str, "[]{}(),;?*=!@") != NULL;
73
0
}
74
75
/**
76
 * Estimates the worst-case scenario for a quoted version of a string's size.
77
 */
78
PHPAPI size_t php_odbc_connstr_estimate_quote_length(const char *in_str)
79
0
{
80
  /* Assume all '}'. Include '{,' '}', and the null terminator too */
81
0
  return (strlen(in_str) * 2) + 3;
82
0
}
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
 */
91
PHPAPI size_t php_odbc_connstr_quote(char *out_str, const char *in_str, size_t out_str_size)
92
0
{
93
0
  *out_str++ = '{';
94
0
  out_str_size--;
95
0
  while (out_str_size > 2) {
96
0
    if (*in_str == '\0') {
97
0
      break;
98
0
    } else if (*in_str == '}' && out_str_size - 1 > 2) {
99
      /* enough room to append */
100
0
      *out_str++ = '}';
101
0
      *out_str++ = *in_str++;
102
0
      out_str_size -= 2;
103
0
    } else if (*in_str == '}') {
104
      /* not enough, truncate here */
105
0
      break;
106
0
    } else {
107
0
      *out_str++ = *in_str++;
108
0
      out_str_size--;
109
0
    }
110
0
  }
111
  /* append termination */
112
0
  *out_str++ = '}';
113
0
  *out_str++ = '\0';
114
0
  out_str_size -= 2;
115
  /* return how many characters were left */
116
0
  return strlen(in_str);
117
0
}