Repository navigation
Expand file tree
/
Copy pathclass.ProwlStack.php
More file actions
292 lines (244 loc) · 9.96 KB
/
Copy pathclass.ProwlStack.php
File metadata and controls
292 lines (244 loc) · 9.96 KB
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
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
<?php
/**
* ProwlStack
* @author Ronnie Moore
* @version 1.0.0
*
* Receives webhook notifications from Formstack of newly-submitted
* web forms and alerts user via Prowl iPhone notification system.
*/
class ProwlStack
{
/**
* Holds all Prowl configuration data
* @var array
*/
var $prowlData;
/**
* Holds all Formstack configuration data
* @var array
*/
var $formstackData;
/**
* Sets up defaults with configuration data for FormStack and Prowl data containers
*/
public function __construct()
{
/* Formstack Data */
$this->formstackData = array();
// defaults
$this->formstackData['SecurityCheckPassed'] = false; // default to not yet passing security check
$this->formstackData['RequiredFormFields'] = array('FormID', 'UniqueID', 'HandshakeKey'); // minimum fields
$this->formstackData['ApiEndpoint'] = 'https://www.formstack.com/api/v2/'; // API v2
/* Prowl Data */
$this->prowlData = array();
$this->prowlData['MessageApplication'] = "ProwlStack"; // 256 char limit
$this->prowlData['MessagePriority'] = 0; // range: [-2, 2] where -2 = Very Low. 0 = Normal. 2 = Emergency.
$this->prowlData['MessageEvent'] = "Submission #{$_POST['UniqueID']}"; // 1024 char limit
$this->prowlData['MessageDescription'] = "A new form submission was received at %DATE%"; // 10000 char limit
// api response info
$this->prowlData['ResponseCode'] = null;
$this->prowlData['ResponseMessage'] = null;
}
/**
* Gets Formstack configuration data
* @param $property
* @return bool|string|array
*/
public function getFormstackData($property)
{
if (isset($this->formstackData) && is_string($property) && array_key_exists($property, $this->formstackData))
{
return $this->formstackData[$property];
}
return false;
}
/**
* Sets Formstack configuration data
* @param $property
* @param null $args
* @return $this|bool
*/
public function setFormstackData($property, $args = null)
{
if (! is_string($property)) return false;
$this->formstackData[$property] = $args;
return $this; // for chaining
}
/**
* Gets Prowl configuration data
* @param $property
* @return bool|string|array
*/
public function getProwlData($property)
{
if (isset($this->prowlData) && is_string($property) && array_key_exists($property, $this->prowlData))
{
return $this->prowlData[$property];
}
return false;
}
/**
* Set Prowl configuration data
* @param $property
* @param null $args
* @return $this|bool
*/
public function setProwlData($property, $args = null)
{
if (! is_string($property)) return false;
$this->prowlData[$property] = $args;
return $this; // for chaining
}
/**
* Validates REQUEST_METHOD used (POST), Formstack HandshakeKey, and minimum required fields
* @return bool
*/
private function securityCheck()
{
// already passed, don't check again
if ($this->getFormstackData('SecurityCheckPassed')) {
return true;
}
// only proceed if we get a POST with our Formstack HandshakeKey
if (/*"POST" != $_SERVER['REQUEST_METHOD'] || */ !isset($_POST['HandshakeKey'])
|| $this->getFormstackData('HandshakeKey') != $_POST['HandshakeKey']) {
echo "Server REQUEST_METHOD and/or HandshakeKey were not accepted.";
return false;
}
// validate defined required fields
foreach ($this->getFormstackData('RequiredFormFields') as $field) {
if (!isset($_POST[$field]) || empty($_POST[$field])) {
echo "Required field: {$field} was not found in this POST submission.";
return false;
}
}
return true; // passed security check
}
/**
* Entry point by webhook listener file to perform security checks and then send the prowl notification
* @return bool
*/
public function processFormStackWebHook()
{
// exit if security check fails
$this->setFormstackData('SecurityCheckPassed', $this->securityCheck());
if (! $this->getFormstackData('SecurityCheckPassed')) {
return false;
}
// send prowl message
$this->sendProwlNotification();
}
/**
* Builds Formstack form field id array and generates Prowl message with merge code support
* @return bool
*/
private function sendProwlNotification()
{
// figures out field labels by calling Formstack API and GET form
// used to customize the prowl notification message
$fieldMap = $this->getFieldMappingsFromFormstackAPI();
// bootstrap to load ProwlPHP source files as needed
require_once dirname(__FILE__) . '/ProwlPHP/bootstrap.php';
$oProwl = new \Prowl\SecureConnector(); // I prefer to use SSL at all times with: \Prowl\SecureConnector
// You can use \Prowl\Connector to make curl NOT use SSL in above line if necessary
$oMsg = new \Prowl\Message();
try {
// required: simple callback filter, needed to handle response
$oProwl->setFilterCallback(function ($sText) {
return $sText;
});
$oProwl->setIsPostRequest(true);
$oMsg->setPriority($this->getProwlData('MessagePriority'));
// You can ADD up to 5 api keys
$oMsg->addApiKey($this->getProwlData('ApiKey'));
$oMsg->setEvent($this->getProwlData('MessageEvent'));
$application = $this->getProwlData('MessageApplication');
if (isset($application) && !empty($application)) {
$oMsg->setApplication($application);
}
// These are optional. Use if provided and not blank
$description = $this->getProwlData('MessageDescription');
if (isset($description) && !empty($description)) {
// the message supports several merge codes for DATE, EMAIL, REQUEST, and FILELINK
$fieldIds = $this->getFormstackData('FieldIds');
// uses field mapping to find correct field id for Email and Request Details
$description = str_replace('%DATE%', date('Y-m-d H:i:s a'), $description);
$description = str_replace('%EMAIL%', $_POST[$fieldIds['Email']], $description);
$description = str_replace('%REQUEST%', $_POST[$fieldIds['Request']], $description);
// merge in FILELINK if a file parameter was found, otherwise use blank string (null)
$fileLink = (isset($_POST[$fieldIds['File']])
&& !empty($_POST[$fieldIds['File']]))
? $_POST[$fieldIds['File']]
: null;
$description = str_replace('%FILELINK%', $fileLink, $description);
// sets the prowl message text
$oMsg->setDescription($description);
}
// send the notification to Prowl API
$oResponse = $oProwl->push($oMsg);
// handle response
if ($oResponse->isError()) { // error
$this->setProwlData('ResponseCode', -1); // unsuccessful
$this->setProwlData('ResponseMessage', $oResponse->getErrorAsString());
echo $this->getProwlData('ResponseMessage');
} else { // success
$this->setProwlData('ResponseCode', 1); // successful
$this->setProwlData('ResponseMessage', "Message sent." . PHP_EOL . "You have " . $oResponse->getRemaining() . " Messages left." . PHP_EOL . "Your counter will reset on " . date('Y-m-d H:i:s', $oResponse->getResetDate()) . PHP_EOL);
}
// response to user
echo $this->getProwlData('ResponseMessage');
return $this->getProwlData('ResponseCode');
} catch (\InvalidArgumentException $argumentException) {
echo $argumentException->getMessage();
} catch (\OutOfRangeException $rangeException) {
echo $rangeException->getMessage();
}
} // end function
/**
* @return array
*/
private function getFieldMappingsFromFormstackAPI()
{
/*
Array
(
[24339317] => your name
[24339318] => email
[24339319] => request details
[24339320] =>
[24339321] => phone
[24339322] => upload a file (optional)
)
*/
//api method/request for my IT Support Requests form
$formId = $this->getFormstackData('FormId');
$token = $this->getFormstackDAta('ApiOauthToken');
$action = "form/{$formId}.json?oauth_token={$token}";
$url = $this->getFormstackData('ApiEndpoint') . $action;
try {
$curl = curl_init();
curl_setopt($curl, CURLOPT_URL, $url);
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
$apiResult = curl_exec($curl);
curl_close($curl);
$form = json_decode($apiResult);
$error = json_last_error();
// if error or we don't get fields returned
if ($error) {
die("Received invalid json from Formstack API: $error <hr><pre>" . stripslashes($apiResult) . "</pre>");
}
// mapping table of field ids to field labels
$fieldMap = array();
foreach ($form->fields as $objField) {
$fieldMap[ $objField->id ] = strtolower($objField->label);
}
return $fieldMap;
} catch (\Exception $exception) {
$exception->getMessage();
$exception->getCode();
die("The Formstack API Error: Code {exception->getCode()}: {$exception->getMessage()}");
}
}
} // end class
?>