38 private static $LTI_VERSIONS = array(self::LTI_VERSION1, self::LTI_VERSION2);
42 private static $MESSAGE_TYPES = array(
'basic-lti-launch-request' =>
'onLaunch',
43 'ContentItemSelectionRequest' =>
'onContentItem',
44 'ToolProxyRegistrationRequest' =>
'register');
50 private static $METHOD_NAMES = array(
'basic-lti-launch-request' =>
'onLaunch',
51 'ContentItemSelectionRequest' =>
'onContentItem',
52 'ToolProxyRegistrationRequest' =>
'onRegister');
65 'custom_lineitems_url',
'custom_results_url',
66 'custom_context_memberships_url');
73 'ext_ims_lis_basic_outcome_url',
'ext_ims_lis_resultvalue_sourcedids',
74 'ext_ims_lis_memberships_id',
'ext_ims_lis_memberships_url',
75 'ext_ims_lti_tool_setting',
'ext_ims_lti_tool_setting_id',
'ext_ims_lti_tool_setting_url',
76 'custom_link_setting_url',
77 'custom_lineitem_url',
'custom_result_url');
84 'User.image' =>
'user_image',
85 'User.username' =>
'username',
86 'User.scope.mentor' =>
'role_scope_mentor',
87 'Membership.role' =>
'roles',
88 'Person.sourcedId' =>
'lis_person_sourcedid',
89 'Person.name.full' =>
'lis_person_name_full',
90 'Person.name.family' =>
'lis_person_name_family',
91 'Person.name.given' =>
'lis_person_name_given',
92 'Person.email.primary' =>
'lis_person_contact_email_primary',
93 'Context.id' =>
'context_id',
94 'Context.type' =>
'context_type',
95 'Context.title' =>
'context_title',
96 'Context.label' =>
'context_label',
97 'CourseOffering.sourcedId' =>
'lis_course_offering_sourcedid',
98 'CourseSection.sourcedId' =>
'lis_course_section_sourcedid',
99 'CourseSection.label' =>
'context_label',
100 'CourseSection.title' =>
'context_title',
101 'ResourceLink.id' =>
'resource_link_id',
102 'ResourceLink.title' =>
'resource_link_title',
103 'ResourceLink.description' =>
'resource_link_description',
104 'Result.sourcedId' =>
'lis_result_sourcedid',
105 'BasicOutcome.url' =>
'lis_outcome_service_url',
106 'ToolConsumerProfile.url' =>
'custom_tc_profile_url',
107 'ToolProxy.url' =>
'tool_proxy_url',
108 'ToolProxy.custom.url' =>
'custom_system_setting_url',
109 'ToolProxyBinding.custom.url' =>
'custom_context_setting_url',
110 'LtiLink.custom.url' =>
'custom_link_setting_url',
111 'LineItems.url' =>
'custom_lineitems_url',
112 'LineItem.url' =>
'custom_lineitem_url',
113 'Results.url' =>
'custom_results_url',
114 'Result.url' =>
'custom_result_url',
115 'ToolProxyBinding.memberships.url' =>
'custom_context_memberships_url');
126 $this->logger =
$DIC->logger()->lti();
127 parent::__construct($dataConnector);
147 ### PROTECTED METHODS
162 if ($this->context instanceof
Context) {
163 $this->context->save();
167 $this->resourceLink->save();
219 if (is_null($callback)) {
220 $callback = self::$METHOD_NAMES[
$_POST[
'lti_message_type']];
222 if (method_exists($this, $callback)) {
224 } elseif (is_null($method) && $this->ok) {
226 $this->reason =
"Message type not supported: {$_POST['lti_message_type']}";
228 if ($this->ok && (
$_POST[
'lti_message_type'] ==
'ToolProxyRegistrationRequest')) {
229 $this->consumer->save();
249 if (!empty($this->returnUrl)) {
250 $errorUrl = $this->returnUrl;
251 if (strpos($errorUrl,
'?') ===
false) {
256 if ($this->debugMode && !is_null($this->reason)) {
257 $errorUrl .=
'lti_errormsg=' . urlencode(
"Debug error: $this->reason");
259 $errorUrl .=
'lti_errormsg=' . urlencode($this->message);
260 if (!is_null($this->reason)) {
261 $errorUrl .=
'<i_errorlog=' . urlencode(
"Debug error: $this->reason");
264 if (!is_null($this->consumer) && isset(
$_POST[
'lti_message_type']) && (
$_POST[
'lti_message_type'] ===
'ContentItemSelectionRequest')) {
265 $formParams = array();
266 if (isset(
$_POST[
'data'])) {
267 $formParams[
'data'] =
$_POST[
'data'];
270 $formParams = $this->consumer->signParameters($errorUrl,
'ContentItemSelection',
$version, $formParams);
271 $page = self::sendForm($errorUrl, $formParams);
274 header(
"Location: {$errorUrl}");
278 if (!is_null($this->errorOutput)) {
279 echo $this->errorOutput;
280 } elseif ($this->debugMode && !empty($this->reason)) {
281 echo
"Debug error: {$this->reason}";
283 echo
"Error: {$this->message}";
286 } elseif (!is_null($this->redirectUrl)) {
287 header(
"Location: {$this->redirectUrl}");
289 } elseif (!is_null($this->output)) {
306 $doSaveConsumer =
false;
308 $this->ok = isset(
$_POST[
'lti_message_type']) && array_key_exists(
$_POST[
'lti_message_type'], self::$MESSAGE_TYPES);
310 $this->reason =
'Invalid or missing lti_message_type parameter.';
313 $this->ok = isset(
$_POST[
'lti_version']) && in_array(
$_POST[
'lti_version'], self::$LTI_VERSIONS);
315 $this->reason =
'Invalid or missing lti_version parameter.';
319 if (
$_POST[
'lti_message_type'] ===
'basic-lti-launch-request') {
320 $this->ok = isset(
$_POST[
'resource_link_id']) && (strlen(trim(
$_POST[
'resource_link_id'])) > 0);
322 $this->reason =
'Missing resource link ID.';
324 } elseif (
$_POST[
'lti_message_type'] ===
'ContentItemSelectionRequest') {
325 if (isset(
$_POST[
'accept_media_types']) && (strlen(trim(
$_POST[
'accept_media_types'])) > 0)) {
326 $mediaTypes = array_filter(explode(
',', str_replace(
' ',
'',
$_POST[
'accept_media_types'])),
'strlen');
327 $mediaTypes = array_unique($mediaTypes);
328 $this->ok = count($mediaTypes) > 0;
330 $this->reason =
'No accept_media_types found.';
332 $this->mediaTypes = $mediaTypes;
337 if ($this->ok && isset(
$_POST[
'accept_presentation_document_targets']) && (strlen(trim(
$_POST[
'accept_presentation_document_targets'])) > 0)) {
338 $documentTargets = array_filter(explode(
',', str_replace(
' ',
'',
$_POST[
'accept_presentation_document_targets'])),
'strlen');
339 $documentTargets = array_unique($documentTargets);
340 $this->ok = count($documentTargets) > 0;
342 $this->reason =
'Missing or empty accept_presentation_document_targets parameter.';
344 foreach ($documentTargets as $documentTarget) {
347 array(
'embed',
'frame',
'iframe',
'window',
'popup',
'overlay',
'none'),
348 'Invalid value in accept_presentation_document_targets parameter: %s.'
355 $this->documentTargets = $documentTargets;
362 $this->ok = isset(
$_POST[
'content_item_return_url']) && (strlen(trim(
$_POST[
'content_item_return_url'])) > 0);
364 $this->reason =
'Missing content_item_return_url parameter.';
367 } elseif (
$_POST[
'lti_message_type'] ==
'ToolProxyRegistrationRequest') {
368 $this->ok = ((isset(
$_POST[
'reg_key']) && (strlen(trim(
$_POST[
'reg_key'])) > 0)) &&
369 (isset(
$_POST[
'reg_password']) && (strlen(trim(
$_POST[
'reg_password'])) > 0)) &&
370 (isset(
$_POST[
'tc_profile_url']) && (strlen(trim(
$_POST[
'tc_profile_url'])) > 0)) &&
371 (isset(
$_POST[
'launch_presentation_return_url']) && (strlen(trim(
$_POST[
'launch_presentation_return_url'])) > 0)));
372 if ($this->debugMode && !$this->ok) {
373 $this->reason =
'Missing message parameters.';
379 $this->logger->debug(
'Checking consumer key...');
382 if ($this->ok && (
$_POST[
'lti_message_type'] !=
'ToolProxyRegistrationRequest')) {
383 $this->ok = isset(
$_POST[
'oauth_consumer_key']);
385 $this->reason =
'Missing consumer key.';
390 $this->ok = !is_null($this->consumer->created);
392 $this->reason =
'Invalid consumer key.';
396 $today = date(
'Y-m-d', $now);
397 if (is_null($this->consumer->lastAccess)) {
398 $doSaveConsumer =
true;
400 $last = date(
'Y-m-d', $this->consumer->lastAccess);
401 $doSaveConsumer = $doSaveConsumer || ($last !== $today);
403 $this->consumer->last_access = $now;
408 $server->add_signature_method($method);
409 $request = OAuth\OAuthRequest::from_request();
411 }
catch (\Exception $e) {
413 if (empty($this->reason)) {
414 if ($this->debugMode) {
416 $signature =
$request->build_signature($method, $consumer,
false);
417 $this->reason = $e->getMessage();
418 if (empty($this->reason)) {
419 $this->reason =
'OAuth exception';
421 $this->details[] =
'Timestamp: ' . time();
422 $this->details[] =
"Signature: {$signature}";
423 $this->details[] =
"Base string: {$request->base_string}]";
425 $this->reason =
'OAuth signature check failed - perhaps an incorrect secret or timestamp.';
432 $today = date(
'Y-m-d', $now);
433 if (is_null($this->consumer->lastAccess)) {
434 $doSaveConsumer =
true;
436 $last = date(
'Y-m-d', $this->consumer->lastAccess);
437 $doSaveConsumer = $doSaveConsumer || ($last !== $today);
439 $this->consumer->last_access = $now;
440 if ($this->consumer->protected) {
441 if (!is_null($this->consumer->consumerGuid)) {
442 $this->ok = empty(
$_POST[
'tool_consumer_instance_guid']) ||
443 ($this->consumer->consumerGuid ===
$_POST[
'tool_consumer_instance_guid']);
445 $this->reason =
'Request is from an invalid tool consumer.';
448 $this->ok = isset(
$_POST[
'tool_consumer_instance_guid']);
450 $this->reason =
'A tool consumer GUID must be included in the launch request.';
455 $this->ok = $this->consumer->enabled;
457 $this->reason =
'Tool consumer has not been enabled by the tool provider.';
461 $this->ok = is_null($this->consumer->enableFrom) || ($this->consumer->enableFrom <= $now);
463 $this->ok = is_null($this->consumer->enableUntil) || ($this->consumer->enableUntil > $now);
465 $this->reason =
'Tool consumer access has expired.';
468 $this->reason =
'Tool consumer access is not yet available.';
474 if (
$_POST[
'lti_message_type'] ===
'ContentItemSelectionRequest') {
475 if (isset(
$_POST[
'accept_unsigned'])) {
476 $this->ok = $this->
checkValue(
$_POST[
'accept_unsigned'], array(
'true',
'false'),
'Invalid value for accept_unsigned parameter: %s.');
478 if ($this->ok && isset(
$_POST[
'accept_multiple'])) {
479 $this->ok = $this->
checkValue(
$_POST[
'accept_multiple'], array(
'true',
'false'),
'Invalid value for accept_multiple parameter: %s.');
481 if ($this->ok && isset(
$_POST[
'accept_copy_advice'])) {
482 $this->ok = $this->
checkValue(
$_POST[
'accept_copy_advice'], array(
'true',
'false'),
'Invalid value for accept_copy_advice parameter: %s.');
484 if ($this->ok && isset(
$_POST[
'auto_create'])) {
485 $this->ok = $this->
checkValue(
$_POST[
'auto_create'], array(
'true',
'false'),
'Invalid value for auto_create parameter: %s.');
487 if ($this->ok && isset(
$_POST[
'can_confirm'])) {
488 $this->ok = $this->
checkValue(
$_POST[
'can_confirm'], array(
'true',
'false'),
'Invalid value for can_confirm parameter: %s.');
490 } elseif (isset(
$_POST[
'launch_presentation_document_target'])) {
492 $_POST[
'launch_presentation_document_target'],
493 array(
'embed',
'frame',
'iframe',
'window',
'popup',
'overlay'),
494 'Invalid value for launch_presentation_document_target parameter: %s.'
500 if ($this->ok && (
$_POST[
'lti_message_type'] ===
'ToolProxyRegistrationRequest')) {
501 $this->ok =
$_POST[
'lti_version'] == self::LTI_VERSION2;
503 $this->reason =
'Invalid lti_version parameter';
506 $http =
new HTTPMessage(
$_POST[
'tc_profile_url'],
'GET',
null,
'Accept: application/vnd.ims.lti.v2.toolconsumerprofile+json');
507 $this->ok =
$http->send();
509 $this->reason =
'Tool consumer profile not accessible.';
511 $tcProfile = json_decode(
$http->response);
512 $this->ok = !is_null($tcProfile);
514 $this->reason =
'Invalid JSON in tool consumer profile.';
522 $this->consumer->profile = $tcProfile;
523 $capabilities = $this->consumer->profile->capability_offered;
525 foreach ($this->resourceHandlers as $resourceHandler) {
526 foreach ($resourceHandler->requiredMessages as
$message) {
527 if (!in_array(
$message->type, $capabilities)) {
532 foreach ($this->constraints as
$name => $constraint) {
533 if ($constraint[
'required']) {
534 if (!in_array(
$name, $capabilities) && !in_array(
$name, array_flip($capabilities))) {
535 $missing[
$name] =
true;
539 if (!empty($missing)) {
541 $this->reason =
'Required capability not offered - \'' . implode(
'\', \
'', array_keys($missing)) .
'\'';
547 foreach ($this->requiredServices as $service) {
548 foreach ($service->formats as
$format) {
549 if (!$this->findService(
$format, $service->actions)) {
551 $this->reason =
'Required service(s) not offered - ';
554 $this->reason .=
', ';
556 $this->reason .=
"'{$format}' [" . implode(
', ', $service->actions) .
']';
562 if (
$_POST[
'lti_message_type'] ===
'ToolProxyRegistrationRequest') {
563 $this->consumer->profile = $tcProfile;
564 $this->consumer->secret =
$_POST[
'reg_password'];
565 $this->consumer->ltiVersion =
$_POST[
'lti_version'];
566 $this->consumer->name = $tcProfile->product_instance->service_owner->service_owner_name->default_value;
567 $this->consumer->consumerName = $this->consumer->name;
568 $this->consumer->consumerVersion =
"{$tcProfile->product_instance->product_info->product_family->code}-{$tcProfile->product_instance->product_info->product_version}";
569 $this->consumer->consumerGuid = $tcProfile->product_instance->guid;
570 $this->consumer->enabled =
true;
571 $this->consumer->protected =
true;
572 $doSaveConsumer =
true;
575 } elseif ($this->ok && !empty(
$_POST[
'custom_tc_profile_url']) && empty($this->consumer->profile)) {
576 $http =
new HTTPMessage(
$_POST[
'custom_tc_profile_url'],
'GET',
null,
'Accept: application/vnd.ims.lti.v2.toolconsumerprofile+json');
578 $tcProfile = json_decode(
$http->response);
579 if (!is_null($tcProfile)) {
580 $this->consumer->profile = $tcProfile;
581 $doSaveConsumer =
true;
613 $this->logger->debug(
'Still ok: ' . ($this->ok ?
'1' :
'0'));
615 $this->logger->debug(
'Reason: ' . $this->reason);
621 if (isset(
$_POST[
'context_id'])) {
622 $this->context = Context::fromConsumer($this->consumer, trim(
$_POST[
'context_id']));
624 if (isset(
$_POST[
'context_title'])) {
628 $title =
"Course {$this->context->getId()}";
630 $this->context->title =
$title;
634 if (isset(
$_POST[
'resource_link_id'])) {
636 if (isset(
$_POST[
'custom_content_item_id'])) {
637 $contentItemId =
$_POST[
'custom_content_item_id'];
639 $this->resourceLink = ResourceLink::fromConsumer($this->consumer, trim(
$_POST[
'resource_link_id']), $contentItemId);
640 if (!empty($this->context)) {
641 $this->resourceLink->setContextId($this->context->getRecordId());
644 if (isset(
$_POST[
'resource_link_title'])) {
648 $title =
"Resource {$this->resourceLink->getId()}";
650 $this->resourceLink->title =
$title;
652 foreach ($this->consumer->getSettings() as
$name => $value) {
653 if (strpos(
$name,
'custom_') === 0) {
654 $this->consumer->setSetting(
$name);
655 $doSaveConsumer =
true;
658 if (!empty($this->context)) {
659 foreach ($this->context->getSettings() as
$name => $value) {
660 if (strpos(
$name,
'custom_') === 0) {
661 $this->context->setSetting(
$name);
665 foreach ($this->resourceLink->getSettings() as
$name => $value) {
666 if (strpos(
$name,
'custom_') === 0) {
667 $this->resourceLink->setSetting(
$name);
671 foreach (self::$LTI_CONSUMER_SETTING_NAMES as
$name) {
675 $this->consumer->setSetting(
$name);
678 if (!empty($this->context)) {
679 foreach (self::$LTI_CONTEXT_SETTING_NAMES as
$name) {
683 $this->context->setSetting(
$name);
687 foreach (self::$LTI_RESOURCE_LINK_SETTING_NAMES as
$name) {
691 $this->resourceLink->setSetting(
$name);
696 if ((strpos(
$name,
'custom_') === 0) &&
697 !in_array(
$name, array_merge(self::$LTI_CONSUMER_SETTING_NAMES, self::$LTI_CONTEXT_SETTING_NAMES, self::$LTI_RESOURCE_LINK_SETTING_NAMES))) {
698 $this->resourceLink->setSetting(
$name, $value);
705 if (isset(
$_POST[
'user_id'])) {
706 $userId = trim(
$_POST[
'user_id']);
709 $this->
user = User::fromResourceLink($this->resourceLink, $userId);
712 $firstname = (isset(
$_POST[
'lis_person_name_given'])) ?
$_POST[
'lis_person_name_given'] :
'';
713 $lastname = (isset(
$_POST[
'lis_person_name_family'])) ?
$_POST[
'lis_person_name_family'] :
'';
714 $fullname = (isset(
$_POST[
'lis_person_name_full'])) ?
$_POST[
'lis_person_name_full'] :
'';
715 $this->
user->setNames($firstname, $lastname, $fullname);
718 $email = (isset(
$_POST[
'lis_person_contact_email_primary'])) ?
$_POST[
'lis_person_contact_email_primary'] :
'';
719 $this->
user->setEmail(
$email, $this->defaultEmail);
722 if (isset(
$_POST[
'user_image'])) {
727 if (isset(
$_POST[
'roles'])) {
728 $this->
user->roles = self::parseRoles(
$_POST[
'roles']);
732 $this->consumer->defaultEmail = $this->defaultEmail;
733 if ($this->consumer->ltiVersion !==
$_POST[
'lti_version']) {
734 $this->consumer->ltiVersion =
$_POST[
'lti_version'];
735 $doSaveConsumer =
true;
737 if (isset(
$_POST[
'tool_consumer_instance_name'])) {
738 if ($this->consumer->consumerName !==
$_POST[
'tool_consumer_instance_name']) {
739 $this->consumer->consumerName =
$_POST[
'tool_consumer_instance_name'];
740 $doSaveConsumer =
true;
743 if (isset(
$_POST[
'tool_consumer_info_product_family_code'])) {
745 if (isset(
$_POST[
'tool_consumer_info_version'])) {
746 $version .=
"-{$_POST['tool_consumer_info_version']}";
749 if ($this->consumer->consumerVersion !==
$version) {
750 $this->consumer->consumerVersion =
$version;
751 $doSaveConsumer =
true;
753 } elseif (isset(
$_POST[
'ext_lms']) && ($this->consumer->consumerName !==
$_POST[
'ext_lms'])) {
754 $this->consumer->consumerVersion =
$_POST[
'ext_lms'];
755 $doSaveConsumer =
true;
757 if (isset(
$_POST[
'tool_consumer_instance_guid'])) {
758 if (is_null($this->consumer->consumerGuid)) {
759 $this->consumer->consumerGuid =
$_POST[
'tool_consumer_instance_guid'];
760 $doSaveConsumer =
true;
761 } elseif (!$this->consumer->protected) {
762 $doSaveConsumer = ($this->consumer->consumerGuid !==
$_POST[
'tool_consumer_instance_guid']);
763 if ($doSaveConsumer) {
764 $this->consumer->consumerGuid =
$_POST[
'tool_consumer_instance_guid'];
768 if (isset(
$_POST[
'launch_presentation_css_url'])) {
769 if ($this->consumer->cssPath !==
$_POST[
'launch_presentation_css_url']) {
770 $this->consumer->cssPath =
$_POST[
'launch_presentation_css_url'];
771 $doSaveConsumer =
true;
773 } elseif (isset(
$_POST[
'ext_launch_presentation_css_url']) &&
774 ($this->consumer->cssPath !==
$_POST[
'ext_launch_presentation_css_url'])) {
775 $this->consumer->cssPath =
$_POST[
'ext_launch_presentation_css_url'];
776 $doSaveConsumer =
true;
777 } elseif (!empty($this->consumer->cssPath)) {
778 $this->consumer->cssPath =
null;
779 $doSaveConsumer =
true;
784 if ($doSaveConsumer) {
785 $this->consumer->save();
787 if ($this->ok && isset($this->context)) {
788 $this->context->save();
794 if ($this->ok && isset($this->resourceLink)) {
799 $this->resourceLink->save();
802 if (isset(
$_POST[
'lis_result_sourcedid'])) {
803 if ($this->
user->ltiResultSourcedId !==
$_POST[
'lis_result_sourcedid']) {
804 $this->
user->ltiResultSourcedId =
$_POST[
'lis_result_sourcedid'];
807 } elseif (!empty($this->
user->ltiResultSourcedId)) {
808 $this->
user->ltiResultSourcedId =
'';
824 $doSaveResourceLink =
true;
826 $id = $this->resourceLink->primaryResourceLinkId;
828 $shareRequest = isset(
$_POST[
'custom_share_key']) && !empty(
$_POST[
'custom_share_key']);
830 if (!$this->allowSharing) {
832 $this->reason =
'Your sharing request has been refused because sharing is not being permitted.';
836 if (!is_null($shareKey->primaryConsumerKey) && !is_null($shareKey->primaryResourceLinkId)) {
838 $key = $shareKey->primaryConsumerKey;
839 $id = $shareKey->primaryResourceLinkId;
840 $ok = (
$key !== $this->consumer->getKey()) || (
$id != $this->resourceLink->getId());
842 $this->resourceLink->primaryConsumerKey =
$key;
843 $this->resourceLink->primaryResourceLinkId =
$id;
844 $this->resourceLink->shareApproved = $shareKey->autoApprove;
845 $ok = $this->resourceLink->save();
847 $doSaveResourceLink =
false;
848 $this->
user->getResourceLink()->primaryConsumerKey =
$key;
849 $this->
user->getResourceLink()->primaryResourceLinkId =
$id;
850 $this->
user->getResourceLink()->shareApproved = $shareKey->autoApprove;
851 $this->
user->getResourceLink()->updated = time();
855 $this->reason =
'An error occurred initialising your share arrangement.';
858 $this->reason =
'It is not possible to share your resource link with yourself.';
864 $this->reason =
'You have requested to share a resource link but none is available.';
866 $ok = (!is_null($this->
user->getResourceLink()->shareApproved) && $this->
user->getResourceLink()->shareApproved);
868 $this->reason =
'Your share request is waiting to be approved.';
877 $this->reason =
'You have not requested to share a resource link but an arrangement is currently in place.';
881 if (
$ok && !is_null(
$id)) {
884 $ok = !is_null($consumer->created);
886 $resourceLink = ResourceLink::fromConsumer($consumer,
$id);
887 $ok = !is_null($resourceLink->created);
890 if ($doSaveResourceLink) {
891 $this->resourceLink->save();
893 $this->resourceLink = $resourceLink;
895 $this->reason =
'Unable to load resource link being shared.';
909 if (!
$ok && !empty($reason)) {
910 $this->reason = sprintf($reason, $value);
foreach($paths as $path) $request
An exception for terminatinating execution or to throw for unit testing.
Class to represent an HTTP message.
Class to represent an OAuth Consumer.
Class to represent an OAuth Data Store.
Class to represent an OAuth Server.
Class to represent an OAuth HMAC_SHA1 signature method.
Class to represent a generic item object.
Class to represent a tool consumer context.
if(!array_key_exists('StateId', $_REQUEST)) $id
if(! $oauthconfig->getBoolean('getUserInfo.enable', FALSE)) $store
catch(Exception $e) $message
foreach($_POST as $key=> $value) $res