forked from ruflin/Elastica
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathUtil.php
206 lines (179 loc) · 6.49 KB
/
Util.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
<?php
declare(strict_types=1);
namespace Elastica;
/**
* Elastica tools.
*
* @author Nicolas Ruflin <[email protected]>
* @author Thibault Duplessis <[email protected]>
* @author Oleg Zinchenko <[email protected]>
* @author Roberto Nygaard <[email protected]>
*/
class Util
{
/** @var list<string> */
protected static $dateMathSymbols = ['<', '>', '/', '{', '}', '|', '+', ':', ','];
/** @var list<string> */
protected static $escapedDateMathSymbols = ['%3C', '%3E', '%2F', '%7B', '%7D', '%7C', '%2B', '%3A', '%2C'];
/**
* Checks if date math is already escaped within request URI.
*
* @param string $requestUri
*
* @return bool
*/
public static function isDateMathEscaped($requestUri)
{
// In practice, the only symbol that really needs to be escaped in URI is '/' => '%2F'
return \str_contains(\strtoupper($requestUri), '%2F');
}
/**
* Escapes date math symbols within request URI.
*
* @see https://www.elastic.co/guide/en/elasticsearch/reference/5.x/date-math-index-names.html
*
* @param string $requestUri
*
* @return string
*/
public static function escapeDateMath($requestUri)
{
if (empty($requestUri)) {
return $requestUri;
}
// Check if date math if used at all. Find last '>'. E.g. /<log-{now/d}>,log-2011.12.01/log/_refresh
$pos1 = \strrpos($requestUri, '>');
if (false === $pos1) {
return $requestUri;
}
// Find the position up to which we should escape.
// Should be next slash '/' after last '>' E.g. /<log-{now/d}>,log-2011.12.01/log/_refresh
$pos2 = \strpos($requestUri, '/', $pos1);
$pos2 = false !== $pos2 ? $pos2 : \strlen($requestUri);
// Cut out the bit we need to escape: /<log-{now/d}>,log-2011.12.01
$uriSegment = \substr($requestUri, 0, $pos2);
// Escape using character map
$escapedUriSegment = \str_replace(static::$dateMathSymbols, static::$escapedDateMathSymbols, $uriSegment);
// '\\{' and '\\}' should not be escaped
if (\str_contains($uriSegment, '\\\\')) {
$escapedUriSegment = \str_replace(['\\\\%7B', '\\\\%7D'], ['\\\\{', '\\\\}'], $escapedUriSegment);
}
// Replace part of the string. E.g. /%3Clog-%7Bnow%2Fd%7D%3E%2Clog-2011.12.01/log/_refresh
return \substr_replace($requestUri, $escapedUriSegment, 0, $pos2);
}
/**
* Replace known reserved words (e.g. AND OR NOT)
* and
* escape known special characters (e.g. + - && || ! ( ) { } [ ] ^ " ~ * ? : etc.).
*
* @see https://www.elastic.co/guide/en/elasticsearch/reference/5.1/query-dsl-query-string-query.html#_boolean_operators
* @see https://www.elastic.co/guide/en/elasticsearch/reference/5.1/query-dsl-query-string-query.html#_reserved_characters
*
* @param string $term Query term to replace and escape
*
* @return string Replaced and escaped query term
*/
public static function replaceBooleanWordsAndEscapeTerm($term)
{
$result = $term;
$result = self::replaceBooleanWords($result);
return self::escapeTerm($result);
}
/**
* Escapes the following terms (because part of the query language)
* + - && || ! ( ) { } [ ] ^ " ~ * ? : \ < >.
*
* @see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#_reserved_characters
*
* @param string $term Query term to escape
*
* @return string Escaped query term
*/
public static function escapeTerm($term)
{
$result = $term;
// \ escaping has to be first, otherwise escaped later once again
$escapableChars = ['\\', '+', '-', '&&', '||', '!', '(', ')', '{', '}', '[', ']', '^', '"', '~', '*', '?', ':', '/'];
foreach ($escapableChars as $char) {
$result = \str_replace($char, '\\'.$char, $result);
}
// < and > cannot be escaped, so they should be removed
// @see https://www.elastic.co/guide/en/elasticsearch/reference/current/query-dsl-query-string-query.html#_reserved_characters
$nonEscapableChars = ['<', '>'];
foreach ($nonEscapableChars as $char) {
$result = \str_replace($char, '', $result);
}
return $result;
}
/**
* Replace the following reserved words (because part of the query language)
* AND OR NOT.
*
* @see http://lucene.apache.org/java/2_4_0/queryparsersyntax.html#Boolean%20operators
*
* @param string $term Query term to replace
*
* @return string Replaced query term
*/
public static function replaceBooleanWords($term)
{
$replacementMap = [' AND ' => ' && ', ' OR ' => ' || ', ' NOT ' => ' !'];
return \strtr($term, $replacementMap);
}
/**
* Converts a snake_case string to CamelCase.
*
* For example: hello_world to HelloWorld
*
* @param string $string snake_case string
*
* @return string CamelCase string
*/
public static function toCamelCase($string)
{
return \str_replace(' ', '', \ucwords(\str_replace('_', ' ', $string)));
}
/**
* Converts a CamelCase string to snake_case.
*
* For Example HelloWorld to hello_world
*
* @param string $string CamelCase String to Convert
*
* @return string SnakeCase string
*/
public static function toSnakeCase($string)
{
return \strtolower(\preg_replace('/[A-Z]/', '_\\0', \lcfirst($string)));
}
/**
* Converts given time to format: 1995-12-31T23:59:59Z.
*
* This is the lucene date format
*
* @param int|string $date Date input (could be string etc.) -> must be supported by strtotime
*
* @return string Converted date string
*/
public static function convertDate($date)
{
if (\is_int($date)) {
$timestamp = $date;
} else {
$timestamp = \strtotime($date);
}
return \date('Y-m-d\TH:i:s\Z', $timestamp);
}
/**
* Convert a \DateTime object to format: 1995-12-31T23:59:59Z+02:00.
*
* Converts it to the lucene format, including the appropriate TimeZone
*
* @return string
*/
public static function convertDateTimeObject(\DateTime $dateTime, bool $includeTimezone = true)
{
$formatString = 'Y-m-d\TH:i:s'.(true === $includeTimezone ? 'P' : '\Z');
return $dateTime->format($formatString);
}
}