How to output in realtime when number is change? - php

I have this code for output :
$tot_clicks6 = $db->FetchArray($db->Query("SELECT SUM(visits) AS sum_visits FROM surf"));
and
<?=$tot_clicks6['sum_visits']?>
is display total of number.

Your question represents a common misconception with PHP. The block of code
<?=$tot_clicks6['sum_visits']?>
Is only that code in your server. As the page is loaded, it gets served as HTML as whatever the value of that variable is. For example,
6
In order to update your page in real time, you need to use AJAX.
See this question
Get variable from PHP file using JQuery/AJAX

Or you can use a real time framework. I work for Realtime.co and we do just that.
You can get a free license at www.realtime.co, get the PHP API at http://www.xrtml.org/downloads_62.html#pubsub:php and use the following code for the page that should broadcast the information (your administration page, for example). Note: this code is the same you can find at Github for the ORTC example (https://github.com/RTWWorld/pubsub-examples/tree/master/PHP) adapted for your needs.
<?php
error_reporting(E_ALL);
session_start();
require('./ortc.php');
/* -------------------- */
/* REPLACE THESE VALUES */
/* -------------------- */
$URL = 'http://ortc-developers.realtime.co/server/2.1';
$AK = 'YOUR_APPLICATION_KEY';// your realtime.co application key
$PK = 'YOUR_APPLICATION_PRIVATE_KEY';// your realtime.co private key
$TK = 'YOUR_AUTHENTICATION_TOKEN';// token: could be randomly generated in the session
$CH = 'MyChannel'; //channel
$ttl = 180;
$isAuthRequired = false;
$result = false;
/* -------------------- */
/* END */
/* -------------------- */
// ORTC auth
// on a live usage we would already have the auth token authorized and stored in a php session
// Since a developer appkey does not require authentication the following code is optional
if( ! array_key_exists('ortc_token', $_SESSION) ){
$_SESSION['ortc_token'] = $TK;
}
$rt = new Realtime( $URL, $AK, $PK, $TK );
// Your query
$tot_clicks6 = $db->FetchArray($db->Query("SELECT SUM(visits) AS sum_visits FROM surf"));
if($isAuthRequired){
$result = $rt->auth(
array(
$CH => 'w'
),
$ttl
);//post authentication permissions. w -> write; r -> read
echo 'authentication status '.( $result ? 'success' : 'failed' ).'<br/>';
}
if($result || !$isAuthRequired){
$result = $rt->send($CH, tot_clicks6['sum_visits'], $response);
echo ' send status '.( $result ? 'success' : 'failed' ).'<br/>';
}
?>
On the receiver page, you'll need to receive the data, using JavaScript and display it. For this example I'm just alerting the user with the data.
<!doctype html>
<html>
<head>
</head>
<body>
<script src="http://code.xrtml.org/xrtml-3.2.0.js"></script>
<script>
var appkey = 'YOUR_APPLICATION_KEY';
var url = 'http://ortc-developers.realtime.co/server/2.1';
var authToken = 'YOUR_AUTHENTICATION_TOKEN';
var channel = 'MyChannel';
xRTML.load(function(){
xRTML.Config.debug = true;
xRTML.ConnectionManager.create({
id: 'myConn',
appkey: appkey,
authToken: authToken,
url: url,
channels: [
{name: channel}
]
}).bind({
message: function(e) {
alert(e);
}
});
});
</script>
</body>
</html>
With this code you won't need to use AJAX or anything like that. You'll be able to push your data to browsers instead.
Hope it helps!

Related

Trying to access unlisted children of root node with phpSmug

I've modified the example-oauth.php file that comes with phpSmug to list the immediate children of the root node, but only public folders (those with at least one public album) and public albums are listed. I know my authorization (Access=Full) is correct, because when I try to list all user albums, I do get them all (code not shown). When I use the live example on the SmugMug site, I do get all immediate children of the root node. So, it seems the problem is within phpSmug, not with the SmugMug API itself. Also, I am replacing a Chrome App that also works as it should. (The Chrome App does not use phpSmug, of course.)
Any idea what's wrong and how I can fix it?
Here's my modified example. Lines that I added or changed are marked with the initials MJR. Note again that I didn't write most of this program, but only added and changed a few lines.
/* Last updated with phpSmug 4.0
*
* This example file shows you how to authenticate using OAuth and then display
* the first 25 images in the first public gallery found of the authenticated
* user's account.
*
* You'll want to set the following variables below:
*
* - $APIKey with one provided by SmugMug: http://www.smugmug.com/hack/apikeys
* - $OAuthSecret with one provided when you obtained your API key
* - $AppName with your application name, version and URL, eg
*
* The $AppName is NOT required, but it's encouraged as it will allow SmugMug to
* diagnose any issues users may have with your application if they request help
* on the SmugMug forums. A good format to use is "APP NAME/VER (URL)".
*
*/
$APIKey = 'YOUR_API_KEY'; // MJR -- my own data was entered
$OAuthSecret = 'YOUR_OAUTH_SECRET'; // MJR -- my own data was entered
$AppName = 'YOUR_APP_NAME/VER (URL)';
?>
<html>
<head>
<title>phpSmug OAuth Login Example</title>
<style type="text/css">
body { background-color: #fff; color: #444; font-family: sans-serif }
div { width: 750px; margin: 0 auto; text-align: center; }
img { border: 0;}
</style>
</head>
<body>
<div>
<img src="phpSmug-logo.svg" />
<h1>OAuth Login Example</h1>
<?php
try {
$options = [
'AppName' => $AppName,
'_verbosity' => 1, # Reduce verbosity to reduce the amount of data in the response and to make using it easier.
'OAuthSecret' => $OAuthSecret, # You need to pass your OAuthSecret in order to authenticate with OAuth.
'verify' => false // MJR: Added because SSL certificates are not set up
];
$client = new phpSmug\Client($APIKey, $options);
// Perform the 3 step OAuth Authorisation process.
// NOTE: This is a very simplified example that does NOT store the final token.
// You will need to ensure your application does.
if (!isset($_SESSION['SmugGalReqToken'])) {
// Step 1: Get a request token using an optional callback URL back to ourselves
$callback = 'http://'.$_SERVER['SERVER_NAME'].':'.$_SERVER['SERVER_PORT'].$_SERVER['SCRIPT_NAME'];
$request_token = $client->getRequestToken($callback);
$_SESSION['SmugGalReqToken'] = serialize($request_token);
// Step 2: Get the User to login to SmugMug and authorise this demo
echo '<p>Click <strong>HERE</strong> to Authorize This Demo.</p>'; // MJR
// Alternatively, automatically direct your visitor by commenting out the above line in favour of this:
//header("Location:".$client->getAuthorizeURL());
} else {
$reqToken = unserialize($_SESSION['SmugGalReqToken']);
unset($_SESSION['SmugGalReqToken']);
// Step 3: Use the Request token obtained in step 1 to get an access token
$client->setToken($reqToken['oauth_token'], $reqToken['oauth_token_secret']);
$oauth_verifier = $_GET['oauth_verifier']; // This comes back with the callback request.
$token = $client->getAccessToken($oauth_verifier); // The results of this call is what your application needs to store.
// Get the username of the authenticated user
$username = $client->get('!authuser')->User->NickName;
// List top level folders and albums. // MJR
$user = $client->get('!authuser'); // MJR
$root = $client->get($user->User->Uris->Node); // MJR
$children = $client->get($root->Node->Uris->ChildNodes); // MJR
foreach ($children->Node as $v) { // MJR
echo "<br> $v->Type \"$v->Name\" $v->Uri"; // MJR
} // MJR
}
} catch (Exception $e) {
echo "{$e->getMessage()} (Error Code: {$e->getCode()})";
}
?>
</div>
</body>
</html>
Your changes should work, and do for me. One thing I did have to do was bump the count of nodes returned as ChildNodes returns only the first 10 nodes by default and my first private album is right at the very end.
Is your first private album/folder outside the first 10? If so, try changing your changes to:
// List top level folders and albums. // MJR
$user = $client->get('!authuser'); // MJR
$root = $client->get($user->User->Uris->Node); // MJR
$children = $client->get($root->Node->Uris->ChildNodes, ['count' => 50]); // MJR
foreach ($children->Node as $v) { // MJR
echo "<br> $v->Type \"$v->Name\" $v->Uri"; // MJR
} // MJR
You'll see I've added ['count' => 50] to the options. You may need to increase this if you've got more than 50 albums/folders.
Alternatively, you can iterate through the pages using the info in $children->Pages.
Solved! I was using an API key that I got a few years ago. I created a new API key, and it works! Must be some weird state left over from before SmugMug went to API 2.
FYI: In the returned JSON, ResponseLevel is now set to Full. If this comes up for anyone else in the future, and you determine that the ResponseLevel is set to Public, that might be a clue that their problem is like mine.
Thanks for your help, lildude. You're a BIG dude in my book!

How to implement Authorize.NET Hosted Payments iFrame & Laravel

I found the official documentation and the github example provided by Authorize.NET to be a terribly confusing mess of stuff you don't need. This post is a summary of the last few hours work hoping it may help others.
This guide assumes you don't want the receipt page and you want to automatically move the user forward on successful payment.
The site back-end is Laravel (PHP) but there's little in here that's Laravel specific.
First thing to do is add the Authorize.NET SDK:
composer require authorizenet/authorizenet
I then setup a hosted payments repository that accepts the order but you could do this however you like, this returns the hosted form token to a controller ready to pass to the view.
<?php
namespace ShopApp\Repositories;
use ShopApp\Models\Order;
use ShopApp\Repositories\Contracts\hostedPaymentRepositoryContract;
use Illuminate\Support\Facades\Config;
use net\authorize\api\contract\v1\MerchantAuthenticationType;
use net\authorize\api\contract\v1\TransactionRequestType;
use net\authorize\api\controller\GetHostedPaymentPageController;
use net\authorize\api\contract\v1\GetHostedPaymentPageRequest;
use net\authorize\api\contract\v1\SettingType;
use net\authorize\api\constants\ANetEnvironment;
use net\authorize\api\contract\v1\CustomerAddressType;
use ShopApp\Models\Address;
/**
* Class hostedPaymentRepository
* #package ShopApp\Repositories
* #todo - Implement methods to talk to Authorize.NET and show form.
*/
class hostedPaymentRepository implements hostedPaymentRepositoryContract
{
public $response; //what did we get back?
public $paymentFormToken;
public function getHostedFormToken(Order $order){
$payment_amount = null;
foreach($order->items as $order_item){
$payment_amount += $order_item->price;
}
$billing_address = Address::findOrFail($order->billing_address_id);
// Common setup for API credentials
$merchantAuthentication = new MerchantAuthenticationType();
$merchantAuthentication->setName(Config::get('yoursite.payment_providers.authorize_dot_net.MERCHANT_LOGIN_ID'));
$merchantAuthentication->setTransactionKey(Config::get('yoursite.payment_providers.authorize_dot_net.MERCHANT_TRANSACTION_KEY'));
//create a transaction
$transactionRequestType = new TransactionRequestType();
$transactionRequestType->setTransactionType("authCaptureTransaction");
$transactionRequestType->setAmount($payment_amount);
// Create the Bill To info
$billto = new CustomerAddressType();
$billto->setFirstName($order->billing_first_name);
$billto->setLastName($order->billing_last_name);
$billto->setAddress($billing_address->address_1);
$billto->setCity($billing_address->city);
$billto->setState($billing_address->state);
$billto->setZip($billing_address->zip);
$billto->setCountry($billing_address->country);
if(!is_null($order->phone)){
$billto->setPhoneNumber($order->phone);
}
//#todo - implement user stuff and get email
//$billto->setEmail("changethis#later.com");
$transactionRequestType->setBillTo($billto);
// Set Hosted Form options
$setting1 = new SettingType();
$setting1->setSettingName("hostedPaymentButtonOptions");
$setting1->setSettingValue("{\"text\": \"Pay Now\"}");
$setting2 = new SettingType();
$setting2->setSettingName("hostedPaymentOrderOptions");
$setting2->setSettingValue("{\"show\": false}");
$setting3 = new SettingType();
$setting3->setSettingName("hostedPaymentReturnOptions");
$setting3->setSettingValue("{\"showReceipt\" : false }");
$setting4 = new SettingType();
$setting4->setSettingName("hostedPaymentIFrameCommunicatorUrl");
$setting4->setSettingValue("{\"url\": \"https://yoursite.local/checkout/payment/response\"}");
// Build transaction request
$request = new GetHostedPaymentPageRequest();
$request->setMerchantAuthentication($merchantAuthentication);
$request->setTransactionRequest($transactionRequestType);
$request->addToHostedPaymentSettings($setting1);
$request->addToHostedPaymentSettings($setting2);
$request->addToHostedPaymentSettings($setting3);
$request->addToHostedPaymentSettings($setting4);
//execute request
$controller = new GetHostedPaymentPageController($request);
$response = $controller->executeWithApiResponse(ANetEnvironment::SANDBOX);
if (($response == null) && ($response->getMessages()->getResultCode() != "Ok") )
{
return false;
}
return $response->getToken();
}
}
Note that I have set showReceipt to false and I have offered another setting called hostedPaymentIFrameCommunicatorUrl. Do not forget the hostedPaymentIFrameCommunicatorUrl otherwise you will get the reciept page regardless of setting showReceipt to false.
The hostedPaymentIFrameCommunicatorUrl MUST be on the same domain as your payment page and on the same port.
Then in your view you need to add the iFrame (mine just sits in the page, i didn't bother with the lightbox:
<div id="iframe_holder" class="center-block" style="width:90%;max-width: 1000px" data-mediator="payment-form-loader">
<iframe id="load_payment" class="embed-responsive-item" name="load_payment" width="750" height="900" frameborder="0" scrolling="no">
</iframe>
<form id="send_hptoken" action="https://test.authorize.net/payment/payment" method="post" target="load_payment">
<input type="hidden" name="token" value="{{ $hosted_payment_form_token }}" />
</form>
</div>
In the same view you need to load at least the following javascript (im using jQuery and have only half implemented the transactResponse method, but you get the idea):
$(document).ready(function(){
window.CommunicationHandler = {};
function parseQueryString(str) {
var vars = [];
var arr = str.split('&');
var pair;
for (var i = 0; i < arr.length; i++) {
pair = arr[i].split('=');
vars[pair[0]] = unescape(pair[1]);
}
return vars;
}
window.CommunicationHandler.onReceiveCommunication = function (argument) {
console.log('communication handler enter');
var params = parseQueryString(argument.qstr)
switch(params['action']){
case "resizeWindow" :
console.log('resize'); break;
case "successfulSave" :
console.log('save'); break;
case "cancel" :
console.log('cancel'); break;
case "transactResponse" :
sessionStorage.removeItem("HPTokenTime");
console.log('transaction complete');
var transResponse = JSON.parse(params['response']);
window.location.href = '/checkout/complete';
}
}
//send the token
$('#send_hptoken').submit();
});
The above code adds a function to handle the message that comes back from the iFrame Communicator (next step) and also submits the payment form token to get and load the actual payment form.
Next we need to setup an 'iframe communicator' This is basically just a way for Authorize.NET to get around the same-domain origin policy
To do this, create a new route and a view that just returns a simple HTML page (or a blade template, but it should have no content other than the scripts).
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>IFrame Communicator</title>
<script type="text/javascript">
function callParentFunction(str) {
if (str && str.length > 0 && window.parent.parent
&& window.parent.parent.CommunicationHandler && window.parent.parent.CommunicationHandler.onReceiveCommunication) {
var referrer = document.referrer;
window.parent.parent.CommunicationHandler.onReceiveCommunication({qstr : str , parent : referrer});
}
}
function receiveMessage(event) {
if (event && event.data) {
callParentFunction(event.data);
}
}
if (window.addEventListener) {
window.addEventListener("message", receiveMessage, false);
} else if (window.attachEvent) {
window.attachEvent("onmessage", receiveMessage);
}
if (window.location.hash && window.location.hash.length > 1) {
callParentFunction(window.location.hash.substring(1));
}
</script>
</head>
<body></body>
</html>
The key part here is the window.parent.parent
Authorize.NET grabs your hostedPaymentIFrameCommunicatorUrl that you gave it in the beginning and embeds this within another iFrame, inside their own payment iFrame. Which is why it's window.parent.parent.
Your hostedPaymentIFrameCommunicatorUrl script then can pass the payment response to your payment page and you can edit the functions above to do what you like after that.
Hope that helps someone.
Authorize.NET is seriously lacking examples and their docs are lightweight at best. The 'catch-all' example that has you sifting through loads of code you don't need is just plain lazy.
Their API doc isn't bad though, they just need decent examples...

ReCaptcha not working properly on iPhone

I have a website with a simple contact form. The validation is somewhat minimal because it doesn't go into a database; just an email. The form works as such:
There are 5 fields - 4 of which are required. The submit is disabled until the 4 fields are valid, and then you can submit it. Then everything is validated on the server again, including the recaptcha (which is not validated by me client side). The whole process is done with ajax, and there are multiple tests that must pass on the server side or 4** headers are returned, and the fail callback handler is called.
Everything works like gangbusters on Chrome on the desktop (I haven't tried other browsers, but I can't imagine why they'd be different), but on the iPhone the reCaptcha always validates even if I don't check the box for the test.
In other words: I still have to fill out the four values correctly in order to submit, but if I don't check the box for the reCaptcha, the request still succeeds.
I can post some code if anyone thinks that would be helpful, but it appears that the problem is with the device and not with the code. Does anyone have any insight into this?
Note: The server side is PHP/Apache if this is helpful.
Update: 5/28/2015:
I'm still debugging this, but it seems like Mobile Safari is ignoring my response headers on my iPhone. When I output the response to the page what I get on Desktop for (data,status,xhr) is:
data: my response which at this point just says error or success -> error
status: error
xhr: {'error',400,'error'}
On Mobile safari:
data: error
status: success
xhr: {'error',200,'success'}
So - it seems like it's just ignoring my response headers. I tried explicitly setting {"headers":{"cache-control":"no-cache"}} but to no avail.
Update: 6/3/2015
Per Request, here is the code. This is almost certainly more than you need. It has also become more obtuse because of the changes I've made to try and fix it. Also note that, while it may appear that there are variables that haven't been defined, they (should) have been defined in other files.
The client side
$('#submit').on('click', function(e) {
$(this).parents('form').find('input').each(function() {
$(this).trigger('blur');
})
var $btn = $(this);
$btn = $btn.button('loading');
var dfr = $.Deferred();
if ($(this).attr('disabled') || $(this).hasClass('disabled')) {
e.preventDefault();
e.stopImmediatePropagation();
dfr.reject();
return false;
} else {
var input = $('form').serializeArray();
var obj = {},
j;
$.each(input, function(i, a) {
if (a.name === 'person-name') {
obj.name = a.value;
} else if (a.name === 'company-name') {
obj.company_name = a.value;
} else {
j = a.name.replace(/(g-)(.*)(-response)/g, '$2');
obj[j] = a.value;
}
});
obj.action = 'recaptcha-js';
obj.remoteIp = rc.remoteiP;
rc.data = obj;
var request = $.ajax({
url: rc.ajaxurl,
type: 'post',
data: obj,
headers: {
'cache-control': 'no-cache'
}
});
var success = function(data) {
$btn.data('loadingText', 'Success');
$btn.button('reset');
$('#submit').addClass('btn-success').removeClass('btn-default');
$btn.button('loading');
dfr.resolve(data);
};
var fail = function(data) {
var reason = JSON.parse(data.responseText).reason;
$btn.delay(1000).button('reset');
switch (reason) {
case 'Recaptcha Failed':
case 'Recaptcha Not Checked':
case 'One Or more validator fields not valid or not filled out':
case 'One Or more validator fields is invalid':
// reset recaptcha
if ($('#submit').data('tries')) {
$('#submit').remove();
$('.g-recaptcha').parent().addBack().remove();
myPopover('Your request is invalid. Please reload the page to try again.');
} else {
$('#submit').data('tries', 1);
grecaptcha.reset();
myPopover('One or more of your entries are invalid. Please make corrections and try again.');
}
break;
default:
// reset page
$('#submit').remove();
$('.g-recaptcha').remove();
myPopover('There was a problem with your request. Please reload the page and try again.');
break;
}
dfr.reject(data);
};
request.done(success);
request.fail(fail);
}
The Server:
function _send_email(){
$recaptcha=false;
/* * */
if(isset($_POST['recaptcha'])):
$gRecaptchaResponse=$_POST['recaptcha'];
$remoteIp=isset($_POST['remoteIp']) ? $_POST['remoteIp'] : false;
/* ** */
if(!$remoteIp):
$response=array('status_code'=>'409','reason'=>'remoteIP not set');
echo json_encode($response);
http_response_code(409);
exit();
endif;
/* ** */
/* ** */
if($gRecaptchaResponse==''):
$response=array('status_code'=>'400','reason'=>'Recaptcha Failed');
echo json_encode($response);
http_response_code(400);
exit();
endif;
/* ** */
if($recaptcha=recaptcha_test($gRecaptchaResponse,$remoteIp)):
$recaptcha=true;
/* ** */
else:
$response=array('status_code'=>'400','reason'=>'Recaptcha Failed');
echo json_encode($response);
http_response_code(400);
exit();
endif;
/* ** */
/* * */
else:
$response=array('status_code'=>'400','reason'=>'Recaptcha Not Checked');
echo json_encode($response);
http_response_code(400);
exit();
endif;
/* * */
/* * */
if($recaptcha==1):
$name=isset($_POST['name']) ? $_POST['name'] : false;
$company_name=isset($_POST['company_name']) ? $_POST['company_name'] : false;
$phone=isset($_POST['phone']) ? $_POST['phone'] : false;
$email=isset($_POST['email']) ? $_POST['email'] : false;
/* ** */
if(isset($_POST['questions'])):
$questions=$_POST['questions']=='' ? 1 : $_POST['questions'];
/* *** */
if(!$questions=filter_var($questions,FILTER_SANITIZE_SPECIAL_CHARS)):
$response=array('status_code'=>'400','reason'=>'$questions could not be sanitized');
echo json_encode($response);
http_response_code(400);
exit();
endif;
/* *** */
/* ** */
else:
$questions=true;
endif;
/* ** */
/* ** */
if( count( array_filter( array( $name,$company_name,$phone,$email ),"filter_false" ) ) !=4 ):
$response=array('status_code'=>'400','reason'=>'One Or more validator fields not valid or not filled out');
echo json_encode($response);
http_response_code(400);
exit();
endif;
/* ** */
$company_name=filter_var($company_name,FILTER_SANITIZE_SPECIAL_CHARS);
$name=filter_var($name,FILTER_SANITIZE_SPECIAL_CHARS);
$phone=preg_replace('/[^0-9+-]/', '', $phone);
$email=filter_var($email,FILTER_VALIDATE_EMAIL);
/* ** */
if($company_name && $recaptcha && $name && $phone && $email && $questions):
$phone_str='Phone: ' . $phone;
$company_str='Company: ' . $company_name;
$email_str='Email String: ' . $email;
$name_str='Name: '.$name;
$questions=$questions==1 ? '' : $questions;
$body="$name_str\r\n\r\n$company_str\r\n\r\n$email_str\r\n\r\n$phone_str\r\n\r\n____________________\r\n\r\n$questions";
$mymail='fake#fake.com';
$headers = array();
$headers[] = "MIME-Version: 1.0";
$headers[] = "Content-type: text/plain; charset=\"utf-8\"";
$headers[] = "From: $email";
$headers[] = "X-Mailer: PHP/" . phpversion();
/* *** */
if(mail('$mymail', 'Information Request from: ' . $name,$body,implode("\r\n",$headers))):
$response=array('status_code'=>'200','reason'=>'Sent !');
echo json_encode($response);
http_response_code(200);
exit();
/* *** */
else:
$response=array('status_code'=>'400','reason'=>'One Or more validator fields is invalid');
echo json_encode($response);
http_response_code(400);
exit();
endif;
/* *** */
endif;
/* ** */
endif;
/* * */
$response=array('status_code'=>'412','reason'=>'There was an unknown error');
echo json_encode($response);
http_response_code(412);
exit();
}
function recaptcha_test($gRecaptchaResponse,$remoteIp){
$secret=$itsasecret; //removed for security;
require TEMPLATE_DIR . '/includes/lib/recaptcha/src/autoload.php';
$recaptcha = new \ReCaptcha\ReCaptcha($secret);
$resp = $recaptcha->verify($gRecaptchaResponse, $remoteIp);
if ($resp->isSuccess()) {
return true;
// verified!
} else {
$errors = $resp->getErrorCodes();
return false;
}
}
Like that question iOS: Authentication using XMLHttpRequest - Handling 401 reponse the easiest way to solve that is disregard natural headers validation and, on the callback sucess, validate with some flag.
I've saw some cases like that and never smell good.
Is your "remoteIP" variable correctly set in the client side?
Even if your Ajax request sends an empty or false value, the isset() function in your php script will return true, and thus populates the $remoteIp wrongly.
Try doing:
$remoteIp = $_SERVER['REMOTE_ADDR'];
Ajax just makes the browser do the request, thus PHP can perfectly grab the ip of our user.
I'm sure that if you're passing the wrong value, ReCaptcha will mess up in one way or another.
It's also safer to never trust any Javascript variables over Ajax, as those should be treated as user input as well.
The captcha is designed to prevent malicious clients (robots), so theoretically if a client bypasses the captcha, it is a server side problem. (However, if a client fails to complete the captcha, it may be a server side problem or a client side problem.)
So the problem must be at the server. Even from security considerations, you should be using $_SERVER['REMOTE_ADDR'] rather than $_POST['remoteIp'] because $_POST['remoteIp'] may be faked (by a malicious client). In fact, $_SERVER['REMOTE_ADDR'] is much more reliable than the client-side $_POST['remoteIp'].
I made a script 2 or 3 months ago that still works perfectly, try this:
<?php
$siteKey = ''; // Public Key
$secret = ''; // Private Key
/**
* This is a PHP library that handles calling reCAPTCHA.
* - Documentation and latest version
* https://developers.google.com/recaptcha/docs/php
* - Get a reCAPTCHA API Key
* https://www.google.com/recaptcha/admin/create
* - Discussion group
* http://groups.google.com/group/recaptcha
*
* #copyright Copyright (c) 2014, Google Inc.
* #link http://www.google.com/recaptcha
*
* Permission is hereby granted, free of charge, to any person obtaining a copy
* of this software and associated documentation files (the "Software"), to deal
* in the Software without restriction, including without limitation the rights
* to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
* copies of the Software, and to permit persons to whom the Software is
* furnished to do so, subject to the following conditions:
*
* The above copyright notice and this permission notice shall be included in
* all copies or substantial portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
* AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
/**
* A ReCaptchaResponse is returned from checkAnswer().
*/
class ReCaptchaResponse
{
public $success;
public $errorCodes;
}
class ReCaptcha
{
private static $_signupUrl = "https://www.google.com/recaptcha/admin";
private static $_siteVerifyUrl =
"https://www.google.com/recaptcha/api/siteverify?";
private $_secret;
private static $_version = "php_1.0";
/**
* Constructor.
*
* #param string $secret shared secret between site and ReCAPTCHA server.
*/
function ReCaptcha($secret)
{
if ($secret == null || $secret == "") {
die("To use reCAPTCHA you must get an API key from <a href='"
. self::$_signupUrl . "'>" . self::$_signupUrl . "</a>");
}
$this->_secret=$secret;
}
/**
* Encodes the given data into a query string format.
*
* #param array $data array of string elements to be encoded.
*
* #return string - encoded request.
*/
private function _encodeQS($data)
{
$req = "";
foreach ($data as $key => $value) {
$req .= $key . '=' . urlencode(stripslashes($value)) . '&';
}
// Cut the last '&'
$req=substr($req, 0, strlen($req)-1);
return $req;
}
/**
* Submits an HTTP GET to a reCAPTCHA server.
*
* #param string $path url path to recaptcha server.
* #param array $data array of parameters to be sent.
*
* #return array response
*/
private function _submitHTTPGet($path, $data)
{
$req = $this->_encodeQS($data);
$response = file_get_contents($path . $req);
return $response;
}
/**
* Calls the reCAPTCHA siteverify API to verify whether the user passes
* CAPTCHA test.
*
* #param string $remoteIp IP address of end user.
* #param string $response response string from recaptcha verification.
*
* #return ReCaptchaResponse
*/
public function verifyResponse($remoteIp, $response)
{
// Discard empty solution submissions
if ($response == null || strlen($response) == 0) {
$recaptchaResponse = new ReCaptchaResponse();
$recaptchaResponse->success = false;
$recaptchaResponse->errorCodes = 'missing-input';
return $recaptchaResponse;
}
$getResponse = $this->_submitHttpGet(
self::$_siteVerifyUrl,
array (
'secret' => $this->_secret,
'remoteip' => $remoteIp,
'v' => self::$_version,
'response' => $response
)
);
$answers = json_decode($getResponse, true);
$recaptchaResponse = new ReCaptchaResponse();
if (trim($answers ['success']) == true) {
$recaptchaResponse->success = true;
} else {
$recaptchaResponse->success = false;
$recaptchaResponse->errorCodes = $answers [error-codes];
}
return $recaptchaResponse;
}
}
$reCaptcha = new ReCaptcha($secret);
if(isset($_POST["g-recaptcha-response"])) {
$resp = $reCaptcha->verifyResponse(
$_SERVER["REMOTE_ADDR"],
$_POST["g-recaptcha-response"]
);
if ($resp != null && $resp->success) {echo "OK";}
else {echo "CAPTCHA incorrect";}
}
?>
<html>
<head>
<title>Google reCAPTCHA</title>
<script src="https://www.google.com/recaptcha/api.js"></script>
</head>
<body>
<form action="reCAPTCHA.php" method="POST">
<input type="submit" value="Submit">
<div class="g-recaptcha" data-sitekey="<?php echo $siteKey; ?>"></div>
</form>
</body>
</html>
Normally, it should work (just add your private key and your public key), I tested on my iPhone SE, 2 seconds ago, and it worked perfectly.

Jquery Ajax and PHP MVC Model

I´m building a small application with Jquery and PHP. Jquery (index.html) adds Form Fields for the User and sends those to a PHP Script (pdo.php). The PHP Script fetches Values from the Database and does some calculations with the User given Values and the Values from the DB. The sum is returned to the Form Page.
index.html <-> pdo.php
Thus I am trying to understand the PHP MVC pattern my question is if
a.) this would make sense in this case.
b.) if so, which part would be what. index.html --> view; pdo.php --> model; controller --> ?
thanks for your help,
tony
Cut-out
jquery ... index.html
$(document).ready(function(){
$("#buttonAjax").click(function(){
var name = encodeURI($("#name").val());
$.ajax({
type: "POST",
url: "pdo.php",
data: "name="+name,
success: function(data){
var json = $.parseJSON(data);
$("#output").html(json.summe);
talk(json.say);
}
});
});
function talk (say){
jQuery.noticeAdd({text: say,stay: false});
}
});
pdo.php
/* DB Connection */
$strDbLocation = 'mysql:dbname=test;host=localhost';
$strDbUser = 'root';
$strDbPassword = 'root';
try{
$objDb = new PDO($strDbLocation, $strDbUser, $strDbPassword);
}
catch (PDOException $e){
echo 'Failure: ' . $e->getMessage();
}
/* Fetch POST Data */
$id = $_POST['name'];
/* Build query */
$dbSelect = $objDb->prepare("SELECT Age,Name FROM Benutzer WHERE id = :id");
$dbSelect -> setFetchMode(PDO::FETCH_ASSOC);
$dbSelect -> bindParam('id', $id);
$dbSelect -> execute();
/* Output + Calculate */
while($row = $dbSelect->fetch()) {
$total = $row['Age'] / 100 . "<br />";
}
/* Return to User */
if(!empty($total)){
$ret = Array("summe" => "Summe: " . $total, "say" => "all right");
echo json_encode($ret); }
else{
$ret = Array("summe" => "Nothing for you", "say" => "nothing for you");
echo json_encode($ret);
}
In a standard MVC webapp, routes are matched to controller actions. These controller actions may interface with the Model [which in turn interfaced with the database] or performs some other Model-agnostic calculations, and renders a view. It is obvious that the index.html is the view. And I think you have the controller and the model bundled up in pdo.php.
I really recommend PeeHaa's link in the comments. That answer is well written.
That been said, there are many architectural patterns to making a webapp. Yours may not be MVC. Some prominent frameworks that aren't MVC are SproutCore (View-based controllers) and JSP pages (single controller).
Use of controller is to controll the form elements in html using php . For eg:
/ * Fetch POST Data */
$id = $_POST['name'];
the use of model is only for db use (insert,select,..)

How to evaluate json member using variable ?

Hi i've got a problem evaluating json. My goal is to insert json member value to a function variable, take a look at this
function func_load_session(svar){
var id = '';
$.getJSON('data/session.php?load='+svar, function(json){
eval('id = json.'+svar);
});
return id;
}
this code i load session from php file that i've store beforehand. i store that session variable using dynamic var.
<?php
/*
* format ?var=[nama_var]&val=[nilai_nama_var]
*/
$var = $_GET['var'];
$val = $_GET['val'];
$load = $_GET['load'];
session_start();
if($var){
$_SESSION["$var"] = $val;
echo "Store SESSION[\"$var\"] = '".$_SESSION["$var"]."'";
}else if($load){
echo $_SESSION["$load"];
}
?>
using firebug, i get expected response but i also received error
> uncaught exception: Syntax error, unrecognized expression: )
pointing at this
> eval('id = json.'+svar);
I wonder how to solve this
The correct code to use is:
id = json[svar];
You may also want to add alert(svar); to check that svar contains the correct value beforehand.
However, your code still won't work: the func_load_session function will return immediately, before the ajax call finishes and before the id variable is assigned.
what you need to do instead is to perform whatever you want to do with id from the ajax callback function:
function func_load_session(svar){
$.getJSON('data/session.php?load='+svar, function(json){
var id = json[svar];
doSomethingWith(id);
});
}
Also If I understand and have full part of your code Your json comes out like Store["var"]="var" ??
Does not appear valid json
I suggest using php function json_encode()
So php would be
$var = $_GET['var'];
$val = $_GET['val'];
$load = $_GET['load'];
session_start();
if($var){
$_SESSION["$var"] = $val;
echo json_encode(array($var=>$_SESSION[$var])); // or something like that
}else if($load){
echo json_encode(array('load'=>$_SESSION["$load"]);
}
?>

Categories