diff --git a/css/inContact.css b/css/inContact.css new file mode 100644 index 0000000..be6ab84 --- /dev/null +++ b/css/inContact.css @@ -0,0 +1 @@ +form #website{ display:none; } \ No newline at end of file diff --git a/in-contact.php b/in-contact.php new file mode 100644 index 0000000..9bed8bb --- /dev/null +++ b/in-contact.php @@ -0,0 +1,26 @@ +secret = $secret; + $this->requestMethod = (is_null($requestMethod)) ? new RequestMethod\Post() : $requestMethod; + } + + /** + * Calls the reCAPTCHA siteverify API to verify whether the user passes + * CAPTCHA test and additionally runs any specified additional checks + * + * @param string $response The user response token provided by reCAPTCHA, verifying the user on your site. + * @param string $remoteIp The end user's IP address. + * @return Response Response from the service. + */ + public function verify($response, $remoteIp = null) + { + // Discard empty solution submissions + if (empty($response)) { + $recaptchaResponse = new Response(false, array(self::E_MISSING_INPUT_RESPONSE)); + return $recaptchaResponse; + } + + $params = new RequestParameters($this->secret, $response, $remoteIp, self::VERSION); + $rawResponse = $this->requestMethod->submit($params); + $initialResponse = Response::fromJson($rawResponse); + $validationErrors = array(); + + if (isset($this->hostname) && strcasecmp($this->hostname, $initialResponse->getHostname()) !== 0) { + $validationErrors[] = self::E_HOSTNAME_MISMATCH; + } + + if (isset($this->apkPackageName) && strcasecmp($this->apkPackageName, $initialResponse->getApkPackageName()) !== 0) { + $validationErrors[] = self::E_APK_PACKAGE_NAME_MISMATCH; + } + + if (isset($this->action) && strcasecmp($this->action, $initialResponse->getAction()) !== 0) { + $validationErrors[] = self::E_ACTION_MISMATCH; + } + + if (isset($this->threshold) && $this->threshold > $initialResponse->getScore()) { + $validationErrors[] = self::E_SCORE_THRESHOLD_NOT_MET; + } + + if (isset($this->timeoutSeconds)) { + $challengeTs = strtotime($initialResponse->getChallengeTs()); + + if ($challengeTs > 0 && time() - $challengeTs > $this->timeoutSeconds) { + $validationErrors[] = self::E_CHALLENGE_TIMEOUT; + } + } + + if (empty($validationErrors)) { + return $initialResponse; + } + + return new Response( + false, + array_merge($initialResponse->getErrorCodes(), $validationErrors), + $initialResponse->getHostname(), + $initialResponse->getChallengeTs(), + $initialResponse->getApkPackageName(), + $initialResponse->getScore(), + $initialResponse->getAction() + ); + } + + /** + * Provide a hostname to match against in verify() + * This should be without a protocol or trailing slash, e.g. www.google.com + * + * @param string $hostname Expected hostname + * @return ReCaptcha Current instance for fluent interface + */ + public function setExpectedHostname($hostname) + { + $this->hostname = $hostname; + return $this; + } + + /** + * Provide an APK package name to match against in verify() + * + * @param string $apkPackageName Expected APK package name + * @return ReCaptcha Current instance for fluent interface + */ + public function setExpectedApkPackageName($apkPackageName) + { + $this->apkPackageName = $apkPackageName; + return $this; + } + + /** + * Provide an action to match against in verify() + * This should be set per page. + * + * @param string $action Expected action + * @return ReCaptcha Current instance for fluent interface + */ + public function setExpectedAction($action) + { + $this->action = $action; + return $this; + } + + /** + * Provide a threshold to meet or exceed in verify() + * Threshold should be a float between 0 and 1 which will be tested as response >= threshold. + * + * @param float $threshold Expected threshold + * @return ReCaptcha Current instance for fluent interface + */ + public function setScoreThreshold($threshold) + { + $this->threshold = floatval($threshold); + return $this; + } + + /** + * Provide a timeout in seconds to test against the challenge timestamp in verify() + * + * @param int $timeoutSeconds Expected hostname + * @return ReCaptcha Current instance for fluent interface + */ + public function setChallengeTimeout($timeoutSeconds) + { + $this->timeoutSeconds = $timeoutSeconds; + return $this; + } +} diff --git a/inc/classes/ReCaptcha/RequestMethod.php b/inc/classes/ReCaptcha/RequestMethod.php new file mode 100644 index 0000000..0a2a671 --- /dev/null +++ b/inc/classes/ReCaptcha/RequestMethod.php @@ -0,0 +1,50 @@ +curl = (is_null($curl)) ? new Curl() : $curl; + $this->siteVerifyUrl = (is_null($siteVerifyUrl)) ? ReCaptcha::SITE_VERIFY_URL : $siteVerifyUrl; + } + + /** + * Submit the cURL request with the specified parameters. + * + * @param RequestParameters $params Request parameters + * @return string Body of the reCAPTCHA response + */ + public function submit(RequestParameters $params) + { + $handle = $this->curl->init($this->siteVerifyUrl); + + $options = array( + CURLOPT_POST => true, + CURLOPT_POSTFIELDS => $params->toQueryString(), + CURLOPT_HTTPHEADER => array( + 'Content-Type: application/x-www-form-urlencoded' + ), + CURLINFO_HEADER_OUT => false, + CURLOPT_HEADER => false, + CURLOPT_RETURNTRANSFER => true, + CURLOPT_SSL_VERIFYPEER => true + ); + $this->curl->setoptArray($handle, $options); + + $response = $this->curl->exec($handle); + $this->curl->close($handle); + + if ($response !== false) { + return $response; + } + + return '{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}'; + } +} diff --git a/inc/classes/ReCaptcha/RequestMethod/Post.php b/inc/classes/ReCaptcha/RequestMethod/Post.php new file mode 100644 index 0000000..a4ff716 --- /dev/null +++ b/inc/classes/ReCaptcha/RequestMethod/Post.php @@ -0,0 +1,88 @@ +siteVerifyUrl = (is_null($siteVerifyUrl)) ? ReCaptcha::SITE_VERIFY_URL : $siteVerifyUrl; + } + + /** + * Submit the POST request with the specified parameters. + * + * @param RequestParameters $params Request parameters + * @return string Body of the reCAPTCHA response + */ + public function submit(RequestParameters $params) + { + $options = array( + 'http' => array( + 'header' => "Content-type: application/x-www-form-urlencoded\r\n", + 'method' => 'POST', + 'content' => $params->toQueryString(), + // Force the peer to validate (not needed in 5.6.0+, but still works) + 'verify_peer' => true, + ), + ); + $context = stream_context_create($options); + $response = file_get_contents($this->siteVerifyUrl, false, $context); + + if ($response !== false) { + return $response; + } + + return '{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}'; + } +} diff --git a/inc/classes/ReCaptcha/RequestMethod/Socket.php b/inc/classes/ReCaptcha/RequestMethod/Socket.php new file mode 100644 index 0000000..236bd5f --- /dev/null +++ b/inc/classes/ReCaptcha/RequestMethod/Socket.php @@ -0,0 +1,112 @@ +handle = fsockopen($hostname, $port, $errno, $errstr, (is_null($timeout) ? ini_get("default_socket_timeout") : $timeout)); + + if ($this->handle != false && $errno === 0 && $errstr === '') { + return $this->handle; + } + return false; + } + + /** + * fwrite + * + * @see http://php.net/fwrite + * @param string $string + * @param int $length + * @return int | bool + */ + public function fwrite($string, $length = null) + { + return fwrite($this->handle, $string, (is_null($length) ? strlen($string) : $length)); + } + + /** + * fgets + * + * @see http://php.net/fgets + * @param int $length + * @return string + */ + public function fgets($length = null) + { + return fgets($this->handle, $length); + } + + /** + * feof + * + * @see http://php.net/feof + * @return bool + */ + public function feof() + { + return feof($this->handle); + } + + /** + * fclose + * + * @see http://php.net/fclose + * @return bool + */ + public function fclose() + { + return fclose($this->handle); + } +} diff --git a/inc/classes/ReCaptcha/RequestMethod/SocketPost.php b/inc/classes/ReCaptcha/RequestMethod/SocketPost.php new file mode 100644 index 0000000..464bc28 --- /dev/null +++ b/inc/classes/ReCaptcha/RequestMethod/SocketPost.php @@ -0,0 +1,108 @@ +socket = (is_null($socket)) ? new Socket() : $socket; + $this->siteVerifyUrl = (is_null($siteVerifyUrl)) ? ReCaptcha::SITE_VERIFY_URL : $siteVerifyUrl; + } + + /** + * Submit the POST request with the specified parameters. + * + * @param RequestParameters $params Request parameters + * @return string Body of the reCAPTCHA response + */ + public function submit(RequestParameters $params) + { + $errno = 0; + $errstr = ''; + $urlParsed = parse_url($this->siteVerifyUrl); + + if (false === $this->socket->fsockopen('ssl://' . $urlParsed['host'], 443, $errno, $errstr, 30)) { + return '{"success": false, "error-codes": ["'.ReCaptcha::E_CONNECTION_FAILED.'"]}'; + } + + $content = $params->toQueryString(); + + $request = "POST " . $urlParsed['path'] . " HTTP/1.0\r\n"; + $request .= "Host: " . $urlParsed['host'] . "\r\n"; + $request .= "Content-Type: application/x-www-form-urlencoded\r\n"; + $request .= "Content-length: " . strlen($content) . "\r\n"; + $request .= "Connection: close\r\n\r\n"; + $request .= $content . "\r\n\r\n"; + + $this->socket->fwrite($request); + $response = ''; + + while (!$this->socket->feof()) { + $response .= $this->socket->fgets(4096); + } + + $this->socket->fclose(); + + if (0 !== strpos($response, 'HTTP/1.0 200 OK')) { + return '{"success": false, "error-codes": ["'.ReCaptcha::E_BAD_RESPONSE.'"]}'; + } + + $parts = preg_split("#\n\s*\n#Uis", $response); + + return $parts[1]; + } +} diff --git a/inc/classes/ReCaptcha/RequestParameters.php b/inc/classes/ReCaptcha/RequestParameters.php new file mode 100644 index 0000000..e9ba453 --- /dev/null +++ b/inc/classes/ReCaptcha/RequestParameters.php @@ -0,0 +1,111 @@ +secret = $secret; + $this->response = $response; + $this->remoteIp = $remoteIp; + $this->version = $version; + } + + /** + * Array representation. + * + * @return array Array formatted parameters. + */ + public function toArray() + { + $params = array('secret' => $this->secret, 'response' => $this->response); + + if (!is_null($this->remoteIp)) { + $params['remoteip'] = $this->remoteIp; + } + + if (!is_null($this->version)) { + $params['version'] = $this->version; + } + + return $params; + } + + /** + * Query string representation for HTTP request. + * + * @return string Query string formatted parameters. + */ + public function toQueryString() + { + return http_build_query($this->toArray(), '', '&'); + } +} diff --git a/inc/classes/ReCaptcha/Response.php b/inc/classes/ReCaptcha/Response.php new file mode 100644 index 0000000..55838c0 --- /dev/null +++ b/inc/classes/ReCaptcha/Response.php @@ -0,0 +1,218 @@ +success = $success; + $this->hostname = $hostname; + $this->challengeTs = $challengeTs; + $this->apkPackageName = $apkPackageName; + $this->score = $score; + $this->action = $action; + $this->errorCodes = $errorCodes; + } + + /** + * Is success? + * + * @return boolean + */ + public function isSuccess() + { + return $this->success; + } + + /** + * Get error codes. + * + * @return array + */ + public function getErrorCodes() + { + return $this->errorCodes; + } + + /** + * Get hostname. + * + * @return string + */ + public function getHostname() + { + return $this->hostname; + } + + /** + * Get challenge timestamp + * + * @return string + */ + public function getChallengeTs() + { + return $this->challengeTs; + } + + /** + * Get APK package name + * + * @return string + */ + public function getApkPackageName() + { + return $this->apkPackageName; + } + /** + * Get score + * + * @return float + */ + public function getScore() + { + return $this->score; + } + + /** + * Get action + * + * @return string + */ + public function getAction() + { + return $this->action; + } + + public function toArray() + { + return array( + 'success' => $this->isSuccess(), + 'hostname' => $this->getHostname(), + 'challenge_ts' => $this->getChallengeTs(), + 'apk_package_name' => $this->getApkPackageName(), + 'score' => $this->getScore(), + 'action' => $this->getAction(), + 'error-codes' => $this->getErrorCodes(), + ); + } +} diff --git a/inc/classes/inContact/AdminMenu.php b/inc/classes/inContact/AdminMenu.php new file mode 100644 index 0000000..1a95873 --- /dev/null +++ b/inc/classes/inContact/AdminMenu.php @@ -0,0 +1,85 @@ +setupHooks(); + } + + protected function setupHooks() + { + add_action('admin_menu', [$this, 'InContactAdminMenu']); + } + + public function InContactAdminMenu($id) + { + add_menu_page('ustawienia inContact', 'inContact', 'manage_options', 'wp-in-contact', array( + $this, + 'InContactSettings' + ), 'dashicons-email', 100); + } + + public function InContactSettings() + { + $updated = isset($_POST['updated']) ? $_POST['updated'] : ''; + $incontactconfig = isset($_REQUEST['incontact-config']) ? $_REQUEST['incontact-config'] : ''; + if ($updated === 'true' || wp_verify_nonce($incontactconfig, 'incontact-update')) { + update_option('incontact-site-key', $_POST['incontact-site-key']); + update_option('incontact-secret-key', $_POST['incontact-secret-key']); + update_option('incontact-target-mail', $_POST['incontact-target-mail']); + ?> + +
+

Ustawienia zostały zapisane!

+
+
+

InContact - Ustawienia

+
+ + + + + + + + + + + + + + + + + +
+

+ +

+
+
addShortcode(); + } + + protected function addShortcode() + { + add_shortcode('in-contact', array( + $this, + 'inContact' + )); + } + + + public function inContact($atts) + { + $em_name = null; + $em_mail = null; + $em_meeessage = null; + $class = null; + $html = null; + $error = null; + $body = null; + $telefon = null; + + if(!empty($_POST['website'])) die(); + $emmsg = (isset($_POST['emmsg']) ? $_POST['emmsg'] : ''); + if(isset($_POST['em_name'])) { $em_name = $_POST['em_name']; } else { + $error .= 'Proszę wprowadź nazwę'; + } + if(isset($_POST['em_mail'])) { $em_mail = $_POST['em_mail']; } else { + $error .= 'Proszę wprowadź adres email'; + } + if(isset($_POST['em_meeessage'])) { $em_meeessage = $_POST['em_meeessage']; } else { + $error .= 'Proszę wprowadź tersć wiadmości'; + } + + $targetEmail = 'To: Tylkofotografia <' .get_option('incontact-target-mail') .'>'; + $mailResult = 0; + $headers = "MIME-Version: 1.0" . "\r\n"; + $headers .= "Content-type: text/html; charset=".get_bloginfo('charset')."" . "\r\n"; + $headers .= "From: " . $em_name ." <".$em_mail.">" . "\r\n"; + $headers = array( + 'Content-Type: text/html; charset=UTF-8', + 'From: ' . $em_name . ' <'.$em_mail.'>', + 'Reply-To: ' . $em_name . ' <'.$em_mail.'>' + ); + + $gRecaptchaResponse = (isset($_POST['g-recaptcha-response']) ? $_POST['g-recaptcha-response'] : ''); + + $body = ' + + + + Nowa wiadomość z formularza kontaktowego + + + +
+
+

📩 Nowa wiadomość z formularza

+
+
+

Dane kontaktowe

+

Imię i nazwisko: {{IMIE_NAZWISKO}}

+

Email: {{EMAIL}}

+ + +
+

📬 Treść wiadomości:

+

{{WIADOMOSC}}

+
+ + Odpowiedz na wiadomość +
+ +
+ + +'; + $body = str_replace( + ['{{IMIE_NAZWISKO}}', '{{EMAIL}}', '{{TELEFON}}', '{{WIADOMOSC}}', '{{ROK}}'], + [$em_name, $em_mail, $telefon, nl2br($em_meeessage), date("Y")], + $body +); + + if (!empty($atts['class'])) { + $class = $atts['class']; + } + if ($emmsg == 'true' && $error) { + $html .= ''; + + } elseif ($emmsg == 'true') + { + + $secret = get_option('incontact-secret-key'); + $response = null; + /*$reCaptcha = new \ReCaptcha\ReCaptcha($secret); + $resp = $reCaptcha->setExpectedHostname($_SERVER['SERVER_NAME'])->verify($gRecaptchaResponse, $_SERVER['REMOTE_ADDR']); + if ($resp->isSuccess()) + {*/ + $mailResult = wp_mail($targetEmail, $em_name, $body, $headers); + /*} + else + { + $errors = $resp->getErrorCodes(); + }*/ + } + + wp_enqueue_style('ContactCss', plugins_url( '/css/cform.css', __FILE__ )); + + $html .= ' + '."\n"; + $html .= '
+
'; + if ($mailResult == 1) + { + $html .= ''; + } + $html .= '
+ + +
+
+ +
+ +
+ Wprowadź nazwę! +
+
+
+
+ +
+ +
+ Podaj adres email! +
+
+
+
+

Wiadomość

+
+ +
+ Wprowadź treść wiadmości! +
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
+
'; + return $html; + } + + + +} \ No newline at end of file diff --git a/inc/classes/inContact/Singleton.php b/inc/classes/inContact/Singleton.php new file mode 100644 index 0000000..dd0aed1 --- /dev/null +++ b/inc/classes/inContact/Singleton.php @@ -0,0 +1,34 @@ +