MediaWiki Authentication from external form - mediawiki

I have already installed mediawiki , but I want to make users authenticate from external authentication form.When they enter the right username and password , they are redirected to the wiki page and do not need to retype the Login data again , and hence they can go to edit the wiki the way they want.How can I achieve that?

Use the mediawiki API with action=login . See http://en.wikipedia.org/w/api.php

If you have external authentication service that provides web authenticaion service you can adapt some webauth extension. This one is used in my organization. You will have to customize it of course.
Yet another option is OpenID login with this extension, looks similar to stackoverflow login.
In these two solutions password is not sent between the "external form" and your wiki, only a token signifying that user passed the login challenge.

see also https://www.mediawiki.org/wiki/User:Krinkle/API_PHP_cURL_example
simple code:
<?php
// Retrieves email address and password from sign-in form
$Username = array_key_exists('username',$_REQUEST)?$_REQUEST['username']:'';
$Password = array_key_exists('password',$_REQUEST)?$_REQUEST['password']:'';
$Action = array_key_exists('action',$_REQUEST)?$_REQUEST['action']:'';
$API_Location = "http://127.0.0.1/w/api.php";
//copied from LocalSettings.php
$wgDBtype = "mysql";
$wgDBserver = "localhost";
$wgDBname = "wiki";
$wgDBuser = "myuser";
$wgDBpassword = "12312312";
$CookiePrefix = 'wiki';
$expire = 60*60*24*365*5 + time();
$CooiePath= null; //='/';
$CookieDomain = null; //'example.com';
function encodeURIComponent($str) {
$revert = array('%21'=>'!', '%2A'=>'*', '%27'=>"'", '%28'=>'(', '%29'=>')');
return strtr(rawurlencode($str), $revert);
}
class curl_onHeaders
{
public $result=array();
function onHeader( $curl, $header_line ) {
$this->result[]=$header_line;
return strlen($header_line);
}
}
function curl($method,$url,$data=false,$headers=false)
{
//$method="PUT"
//$url ="http://example.com";
//$data = "The updated text message";
//$headers=array(); $headers[] = 'Accept: text/html';
$ch = curl_init();
if($data!==false)
{
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch,CURLOPT_POSTFIELDS,$data); // any post data, a string like param1=a&param2=b
}
if($headers!==false)
curl_setopt($ch, CURLOPT_HTTPHEADER, $headers);
curl_setopt($ch, CURLOPT_URL,$url);
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $method); //for updating we have to use PUT method.
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
$onHeader = new curl_onHeaders();
curl_setopt($ch, CURLOPT_HEADERFUNCTION, array(&$onHeader, 'onHeader'));
$result = curl_exec($ch);
$httpCode = curl_getinfo($ch, CURLINFO_HTTP_CODE);
curl_close($ch);
$object = new stdClass();
$object->result = $result;
$object->code = $code;
$object->headers = $onHeader->result;
if(curl_errno($ch))
throw new Exception("curl error: ". curl_error($ch));
//$object->error =curl_error($ch);
return $object;
}
function getcookies($headers)
{
$cookies='';
foreach( $headers as $header)
{
if (preg_match('/^Set-Cookie:\s*([^;]*)/mi', $header, $cookie) == 1)
{
if($cookies==='')
$cookies = $cookie[1];
else
$cookies .="; ".$cookie[1];
}
}
return $cookies;
}
function mearge_cookies($old,$new)
{
// cookies like session are sent only once from server, multiple cookies generally can be mearged with "; "
// a cookie jar is prefered but this code generally fine.
// folowing code does not handle expires
//
// cookie format: https://msdn.microsoft.com/en-us/library/windows/desktop/aa384321(v=vs.85).aspx
//
// Set-Cookie: <name>=<value>[; <name>=<value>]...
// [; expires=<date>][; domain=<domain_name>]
// [; path=<some_path>][; secure][; httponly]
//
// <date> format:
// DAY, DD-MMM-YYYY HH:MM:SS GMT
// DAY The day of the week (Sun, Mon, Tue, Wed, Thu, Fri, Sat).
// DD The day in the month (such as 01 for the first day of the month).
// MMM The three-letter abbreviation for the month (Jan, Feb, Mar, Apr, May, Jun, Jul, Aug, Sep, Oct, Nov, Dec).
// YYYY The year.
// HH The hour value in military time (22 would be 10:00 P.M., for example).
// MM The minute value.
// SS The second value.
$cookiesa=array();
$cookies_strs_to_merge=array($old,$new);
foreach($cookies_strs_to_merge as $cookies_str)
{
foreach(preg_split("/\\s*;\\s*/",$cookies_str) as $cookie)
{
$pcookie=preg_split("/\\s*=\\s*/",$cookie);
$cookie_name=$pcookie[0];
$cookie_value=$pcookie[1];
if(sizeof($pcookie)>1)
{
if($cookie_name=='domain') continue;
if($cookie_name=='expires') continue;
if($cookie_name=='path') continue;
$cookiesa[$cookie_name]=$cookie_value;
}
else if($cookie=='secure' )continue;
else if($cookie=='httponly' )continue;
}
}
$cookies='';
foreach($cookiesa as $cookie_name=>$cookie_value)
$cookies.=($cookies===''?'':'; ').$cookie_name.'='.$cookie_value;
return $cookies;
}
//echo mearge_cookies("aaa=vsdfvsdfv; bbb=asdfasdfasf","aaa=222; ccc=123123"); die;
//$res=curl("GET",'http://doodkin.com');
//$lastcookies=getcookies($res->headers);
//$res=curl("GET",'http://doodkin.com',false,array('Cookie: '.$lastcookies));
//$lastcookies=mearge_cookies($lastcookies, getcookies($res->headers) );
mysql_connect($wgDBserver, $wgDBuser, $wgDBpassword) or die('Could not connect: ' . mysql_error());
if($Action == 'login')
{
// Query to retrieve username from database based on email. It is implied that authentication has already succeeded.
$Query = "SELECT Username FROM `$wgDBname`.Accounts WHERE Email = '".mysql_escape_string($Username)."'";
$ResultSet = mysql_query($Query);
if(mysql_num_rows($Query))
{
$ResultArray = mysql_fetch_array($ResultSet);
$Username = $ResultArray[0]; // Username
}
mysql_free_result($ResultSet);
// first http post to sign in to MediaWiki
$res=curl("POST",$API_Location,"action=login&lgname=".encodeURIComponent($Username)."&lgpassword=".encodeURIComponent($Password)."&format=php");
$lastcookies=getcookies($res->headers);
$result = unserialize($res->result);
$Token = $result[login][token];
// cookie must be set using session id from first response
$WikiSessionID = $result[login][sessionid];
setcookie("${CookiePrefix}_session", $WikiSessionID, $expire, $CooiePath, $CookieDomain);
// second http post to finish sign in
if ($result["login"]["result"] == "NeedToken") {
$res=curl("POST",$API_Location,"action=login&lgname=".encodeURIComponent($Username)."&lgpassword=".encodeURIComponent($Password)."&lgtoken=".encodeURIComponent($Token)."&format=php",array('Cookie: '.$lastcookies));
$result = unserialize($res->result);
}
if ($result["login"]["result"] == "Success") {
$error = 'ok';
// set persistent cookies
$LgToken = $result["login"]["lgtoken"];
$LgUserID = $result["login"]["lguserid"];
$LgUserName = $result["login"]["lgusername"];
$cookieprefix = $result["login"]["cookieprefix"];
if($cookieprefix!=$CookiePrefix) throw new Exception('notice a wrong cookie prefix');
$_COOKIE["${CookiePrefix}UserName"]=$LgUserName;
$_COOKIE["${CookiePrefix}UserID"]=$LgUserID;
$_COOKIE["${CookiePrefix}Token"]=$LgToken;
$_COOKIE["${CookiePrefix}_session"]=$WikiSessionID;
setcookie("${CookiePrefix}UserName", $LgUserName, $expire, $CooiePath, $CookieDomain);
setcookie("${CookiePrefix}UserID", $LgUserID, $expire, $CooiePath, $CookieDomain);
setcookie("${CookiePrefix}Token", $LgToken, $expire, $CooiePath, $CookieDomain);
} else if ($result["login"]["result"] == "NeedToken") {
$error = "Error 005: Token error. second request.";
} else if ($result["login"]["result"] == "NoName") {
$error = "The username can not be blank";
} else if ($result["login"]["result"] == "Illegal") {
$error = "You provided an illegal username";
} else if ($result["login"]["result"] == "NotExists") {
$error = "The username you provided doesn't exist";
} else if ($result["login"]["result"] == "EmptyPass") {
$error = "The password can not be blank";
} else if ($result["login"]["result"] == "WrongPass" || $result["login"]["result"] == "WrongPluginPass") {
$error = "The password you provided is incorrect";
} else if ($result["login"]["result"] == "CreateBlocked") {
$error = "Autocreation was blocked from this IP address";
} else if ($result["login"]["result"] == "Throttled") {
$error = "You've logged in too many times in a short time. Try again later.";
} else if ($result["login"]["result"] == "mustbeposted") {
$error = "Error 004: Logindata was not send correctly";
} else if ($result["login"]["result"] == "Blocked") {
$error = "This account is blocked.";
} else if ($result["login"]["result"]){
$error = "Error 001: An unknown event occurred.";
} else {
$error = "Error 002: An unknown event occurred.";
}
echo $error;
}
if($Action == "logout")
{
// first http post to sign in to MediaWiki
$_session = array_key_exists("${CookiePrefix}_session",$_COOKIE)?$_COOKIE["${CookiePrefix}_session"]:'';
$UserName = array_key_exists("${CookiePrefix}UserName",$_COOKIE)?$_COOKIE["${CookiePrefix}UserName"]:'';
$UserID = array_key_exists("${CookiePrefix}UserID",$_COOKIE)?$_COOKIE["${CookiePrefix}UserID"]:'';
$Token = array_key_exists("${CookiePrefix}Token",$_COOKIE)?$_COOKIE["${CookiePrefix}Token"]:'';
$headers=array( "Cookie: ".
"${CookiePrefix}_session=".encodeURIComponent($_session)."; ".
"${CookiePrefix}UserName=".encodeURIComponent($UserName)."; ".
"${CookiePrefix}UserID=".encodeURIComponent($UserID)."; ".
"${CookiePrefix}Token=".encodeURIComponent($Token) );
$res=curl("POST",$API_Location,"action=logout",$headers);
$LogoutReturn = unserialize($res->result);
// destroys persistent cookies and ends session
$expire = time() - 60*60*24*90;
setcookie('Session', '', $expire, $CooiePath, $CookieDomain);
setcookie("${CookiePrefix}_session", '', $expire, $CooiePath, $CookieDomain);
setcookie("${CookiePrefix}UserName", '', $expire, $CooiePath, $CookieDomain);
setcookie("${CookiePrefix}UserID", '', $expire, $CooiePath, $CookieDomain);
setcookie("${CookiePrefix}Token", '', $expire, $CooiePath, $CookieDomain);
unset($_COOKIE["${CookiePrefix}UserName"]);
unset($_COOKIE["${CookiePrefix}UserID"]);
unset($_COOKIE["${CookiePrefix}Token"]);
unset($_COOKIE["${CookiePrefix}_session"]);
echo "logout";
}
function checklogin()
{
global $CookiePrefix,$wgDBname;
if( array_key_exists("${CookiePrefix}_session",$_COOKIE)
&& array_key_exists("${CookiePrefix}UserID",$_COOKIE)
)
{
$UserID = intval($_COOKIE["${CookiePrefix}UserID"]);
$UserName = array_key_exists("${CookiePrefix}UserName",$_COOKIE)?$_COOKIE["${CookiePrefix}UserName"]:'';
$Token = array_key_exists("${CookiePrefix}Token",$_COOKIE)?$_COOKIE["${CookiePrefix}Token"]:'';
($result=mysql_query("Select user_name,user_real_name,user_email,user_token,user_token,(Select ug_user from `$wgDBname`.user_groups WHERE ug_group='sysop' and ug_user=user.user_id) as perms from `$wgDBname`.user user WHERE user_id=$UserID"))||die(mysql_error());
$udata=mysql_fetch_object($result);
mysql_free_result($result);
if ($udata!=null)
{
if ( $udata->perms!=null )
{
$level = 1;
}
if($UserName!=$udata->user_name)
{
echo "different username. cookie vs db. can not auto login from mediawiki";
return null;
}
if($Token!=$udata->user_token) {
echo "different token. cookie vs db. can not auto login from mediawiki";
return null;
}
return array(
'UniqueID' => $UserID,
'Name' => $UserName,
'Title' => $udata->user_real_name==""?NULL:$udata->user_real_name,
'Email' => $udata->user_email==""?'no#email.com':$udata->user_email,
'Admin' => $level
);
}
return null;
}
}
?>
<?
$user=checklogin();
if($user!=null)
{
?>
welcome <?=$user['Title']? $user['Title']:$user['Name'] ?>. <br>
logout
<?
}
else
{
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- The above 3 meta tags *must* come first in the head; any other head content must come *after* these tags -->
<title>Signin</title>
<!-- Bootstrap core CSS -->
<link href="https://cdnjs.cloudflare.com/ajax/libs/twitter-bootstrap/4.0.0-alpha/css/bootstrap.css" rel="stylesheet">
<!--[if eq IE 10]>
<style type="text/css">
/*!
* IE10 viewport hack for Surface/desktop Windows 8 bug
* http://getbootstrap.com/getting-started/#support-ie10-width
*/
#-webkit-viewport { width: device-width; }
#-moz-viewport { width: device-width; }
#-ms-viewport { width: device-width; }
#-o-viewport { width: device-width; }
#viewport { width: device-width; }
</style>
<![endif]-->
<!-- Custom styles for this template -->
<style type="text/css">
body {
padding-top: 40px;
padding-bottom: 40px;
background-color: #eee;
}
.form-signin {
max-width: 330px;
padding: 15px;
margin: 0 auto;
}
.form-signin .form-signin-heading,
.form-signin .checkbox {
margin-bottom: 10px;
}
.form-signin .checkbox {
font-weight: normal;
}
.form-signin .form-control {
position: relative;
height: auto;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
box-sizing: border-box;
padding: 10px;
font-size: 16px;
}
.form-signin .form-control:focus {
z-index: 2;
}
.form-signin input[type="email"] {
margin-bottom: -1px;
border-bottom-right-radius: 0;
border-bottom-left-radius: 0;
}
.form-signin input[type="password"] {
margin-bottom: 10px;
border-top-left-radius: 0;
border-top-right-radius: 0;
}
</style>
<!-- HTML5 shim and Respond.js for IE8 support of HTML5 elements and media queries -->
<!--[if lt IE 9]>
<script src="https://oss.maxcdn.com/html5shiv/3.7.2/html5shiv.min.js"></script>
<script src="https://oss.maxcdn.com/respond/1.4.2/respond.min.js"></script>
<![endif]-->
</head>
<body>
<div class="container">
<form class="form-signin" action="<?=$_SERVER['PHP_SELF']?>" method="post" ><input type="hidden" name="action" value="login">
<h2 class="form-signin-heading">Please sign in</h2>
<label for="inputEmail" class="sr-only">Username or Email address</label>
<input type="text" id="inputEmail" class="form-control" name="username" placeholder="Username Or Email address" required autofocus>
<label for="inputPassword" class="sr-only">Password</label>
<input type="password" id="inputPassword" name="password" class="form-control" placeholder="Password" required>
<!-- <div class="checkbox">
<label>
<input type="checkbox" value="remember-me"> Remember me
</label>
</div> -->
<button class="btn btn-lg btn-primary btn-block" type="submit">Sign in</button>
</form>
</div> <!-- /container -->
<!--[if eq IE 10]>
<script type="application/javascript">
/*!
* IE10 viewport hack for Surface/desktop Windows 8 bug
* Copyright 2014-2015 Twitter, Inc.
* Licensed under MIT (https://github.com/twbs/bootstrap/blob/master/LICENSE)
*/
// See the Getting Started docs for more information:
// http://getbootstrap.com/getting-started/#support-ie10-width
(function () {
'use strict';
if (navigator.userAgent.match(/IEMobile\/10\.0/)) {
var msViewportStyle = document.createElement('style')
msViewportStyle.appendChild(
document.createTextNode(
'#-ms-viewport{width:auto!important}'
)
)
document.querySelector('head').appendChild(msViewportStyle)
}
})();
</script>
<![endif]-->
</body>
</html>
<?
}
#mysql_close($conn);
?>

Related

PHP MQTT subscribe not consistent

I am trying to display some values using MQTT on a PHP based page. The PHP code contains the subscriber. I am using Bluemix IoT service for the MQTT broker. Also, the messages are published via Python code on local machine.
When I try to display values on pages using page refresh, the page sometimes fails to display the values. There is no problem at the publisher end as the values are successfully displayed by Bluemix IoT service.
My code is as follows:
<?php
// include class
require('phpMQTT.php');
// set configuration values
if( getenv("VCAP_SERVICES") ) {
// get MySQL service configuration from Bluemix
$services = getenv("VCAP_SERVICES");
$services_json = json_decode($services, true);
$mysql_config = $services_json["iotf-service"][0]["credentials"];
$org_id = $mysql_config["org"];
$port = $mysql_config["mqtt_u_port"];
$username = $mysql_config["apiKey"];
$password = $mysql_config["apiToken"];
}
// set configuration values
$config = array(
'org_id' => $org_id,
'port' => $port,
'app_id' => 'm',
'iotf_api_key' => $username,
'iotf_api_secret' => $password,
'device_id' => 'trial',
'qos' => 1
);
global $Val_A;
global $Val_B;
global $Val_C;
global $Val_D;
//Read already existing file
$ini_b = parse_ini_file("data.ini",true);
$Val_A = $ini_b['Data']['A'];
$Val_B = $ini_b['Data']['B'];
$Val_C = $ini_b['Data']['C'];
$Val_D = $ini_b['Data']['D'];
$config['server'] = $config['org_id'] . '.messaging.internetofthings.ibmcloud.com';
$config['client_id'] = 'a:' . $config['org_id'] . ':' . $config['app_id'];
#echo $config['client_id'];
// initialize client
$mqtt_dev = new phpMQTT($config['server'], $config['port'], $config['client_id']);
$mqtt_dev->debug = false;
// connect to broker
if(!$mqtt_dev->connect(true, null, $config['iotf_api_key'], $config['iotf_api_secret'])){
echo 'ERROR: Could not connect to IoT cloud';
exit();
}
else
{
#echo "Success";
}
$topics['iot-2/type/newdevice/id/' . $config['device_id'] . '/evt/status/fmt/json'] =
array('qos' =>1, 'function' => 'getLocation');
$mqtt_dev->subscribe($topics, 1);
$elapsedSeconds = 0;
while ($mqtt_dev->proc(true)) {
#echo json_encode($json);
if (count($location) == 2) {
break;
}
if ($elapsedSeconds == 5) {
break;
}
$elapsedSeconds++;
sleep(1);
}
// disconnect
//I have tried commenting this too
$mqtt_dev->close();
function getLocation($topic, $msg) {
global $location;
global $json;
$json = json_decode($msg);
$Val_A = $json->A;
$Val_B = $json->B;
$Val_C = $json->C;
$Val_D = $json->D;
//Read already existing file
$ini_backup = parse_ini_file("data.ini",true);
$ValA_b = $ini_backup['Data']['A'];
$ValB_b = $ini_backup['Data']['B'];
$ValC_b = $ini_backup['Data']['C'];
$ValD_b = $ini_backup['Data']['D'];
if($Val_A != 0)
{
$ValA_b = $Val_A;
}
else
{
$Val_A = $ValA_b;
}
if($Val_B != 0)
{
$ValB_b = $Val_B;
}
else
{
$Val_B = $ValB_b;
}
if($Val_C != 0)
{
$ValC_b = $Val_C;
}
else
{
$Val_C = $ValC_b;
}
if($Val_D != 0)
{
$ValD_b = $Val_D;
}
else
{
$Val_D = $ValD_b;
}
$file = fopen("data.ini","w");
fwrite($file,"[Data]". "\n" );
fwrite($file,"A =" . $ValA_b . "\n" );
fwrite($file,"B =" . $ValB_b . "\n" );
fwrite($file,"C =" . $ValC_b . "\n" );
fwrite($file,"D =" . $ValD_b . "\n" );
fclose($file);
return $location;
}
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta http-equiv="refresh" content="5" >
<div id="footer">
This page will automatically reload every 5 seconds. <br/>
</div>
<label for="A">A</label>
<input type="text" value="<?php echo $Val_A ?>" />
<label for="B">B</label>
<input type="text" value="<?php echo $Val_B ?>" />
<label for="C">C</label>
<input type="text" value="<?php echo $Val_C ?>" />
<label for="D">D</label>
<input type="text" value="<?php echo $Val_D ?>" />
</body>
</html>
Can some one guide where am I going wrong?
Rather than using meta to specify the refresh, try using php header("Refresh:5");
There is an old stack overflow thread discussing using meta versus header for refrseh in php.

In fine uploader, how to edit/update S3 file metadata for files that are uploaded in previous sessions?

I have requirement in which user need to edit/update the s3 file metadata that are uploaded in the previous sessions. I have implemented Initial File List, but I need to make file metadata (filename, caption - new field in my case) editable in the display list. Can it be accomplished?
I see edit files feature, but that is limited to before file gets uploaded. Looks like my requirement not easily supported out of the box FU. I have followed below approach.
In template I have a button with text 'Update Caption', which has onclick="captionUpdate()",that will set JS variable(isCaptionUpdate) to true.
Caption update will trigger DeleteFile endpoint except that it will set param data for caption value from text field that is defines in template
In server side code, the process checks for Caption param, and then call function updateObjectWithCaption()
All of the above works seamlessly with following challenges.Please see the screenshot.
When user click on 'Update Caption', it follows DELETE steps and since I am passing Caption param, it updates S3 file. But problem is in the file list, I will see a status text called 'Deleting.....' appears for brief time. How can I change status to 'Updating Caption....' or something similar
Another issue with #1 is that as soon as S3 update, the File in file list gets removed. UI part still thinks that it is DELETE step for some reason, how can I say to UI that it not really delete?
As you can see in the deleteFile section of JS, caption is taken from document.getElementById('caption').value; that means, even if I click 'Update Caption' of 2nd or 3rd or 4th files, it is taking first occurrence of Caption element. How can I get the caption of the specific file ?
Last but not least, how can I show 'Update Caption' button only for previously uploaded file. I do not want show this button on fresh upload.
Sorry for too many question. I could not separate these question as they are all related to S3 file metadata update topic.
Template:
<div class="qq-uploader-selector qq-uploader" qq-drop-area-text="Drop files here">
<div class="qq-total-progress-bar-container-selector qq-total-progress-bar-container">
<div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-total-progress-bar-selector qq-progress-bar qq-total-progress-bar"></div>
</div>
<div class="qq-upload-drop-area-selector qq-upload-drop-area" qq-hide-dropzone>
<span class="qq-upload-drop-area-text-selector"></span>
</div>
<div class="buttons">
<div class="qq-upload-button-selector qq-upload-button">
<div>Select files</div>
</div>
<button type="button" id="trigger-upload-section1" class="btn btn-primary">
<i class="icon-upload icon-white"></i> Upload
</button>
</div>
<span class="qq-drop-processing-selector qq-drop-processing">
<span>Processing dropped files...</span>
<span class="qq-drop-processing-spinner-selector qq-drop-processing-spinner"></span>
</span>
<ul class="qq-upload-list-selector qq-upload-list" aria-live="polite" aria-relevant="additions removals">
<li>
<div class="qq-progress-bar-container-selector">
<div role="progressbar" aria-valuenow="0" aria-valuemin="0" aria-valuemax="100" class="qq-progress-bar-selector qq-progress-bar"></div>
</div>
<span class="qq-upload-spinner-selector qq-upload-spinner"></span>
<img class="qq-thumbnail-selector" qq-max-size="100" qq-server-scale>
<span class="qq-upload-file-selector qq-upload-file"></span>
<span class="qq-edit-filename-icon-selector qq-edit-filename-icon qq-editable" aria-label="Edit filename"></span>
<input class="qq-edit-filename-selector qq-edit-filename" tabindex="0" type="text">
<span class="qq-upload-caption-selector qq-upload-caption"></span>
<span class="qq-edit-caption-icon-selector qq-edit-caption-icon qq-editable" aria-label="Edit caption"></span>
<input class="qq-edit-caption-selector qq-edit-caption qq-editing" placeholder="Caption here ..." tabindex="0" type="text" id="caption">
<span class="qq-upload-size-selector qq-upload-size"></span>
<button type="button" class="qq-btn qq-upload-cancel-selector qq-upload-cancel">Cancel</button>
<button type="button" class="qq-btn qq-upload-retry-selector qq-upload-retry">Retry</button>
<button type="button" class="qq-btn qq-upload-delete-selector qq-upload-delete">Delete</button>
<button type="button" class="qq-btn qq-upload-delete-selector qq-upload-delete" onclick="captionUpdate();">Update Caption</button>
<span role="status" class="qq-upload-status-text-selector qq-upload-status-text"></span>
</li>
</ul>
<dialog class="qq-alert-dialog-selector">
<div class="qq-dialog-message-selector"></div>
<div class="qq-dialog-buttons">
<button type="button" class="qq-cancel-button-selector">Close</button>
</div>
</dialog>
<dialog class="qq-confirm-dialog-selector">
<div class="qq-dialog-message-selector"></div>
<div class="qq-dialog-buttons">
<button type="button" class="qq-cancel-button-selector">No</button>
<button type="button" class="qq-ok-button-selector">Yes</button>
</div>
</dialog>
<dialog class="qq-prompt-dialog-selector">
<div class="qq-dialog-message-selector"></div>
<input type="text">
<div class="qq-dialog-buttons">
<button type="button" class="qq-cancel-button-selector">Cancel</button>
<button type="button" class="qq-ok-button-selector">Ok</button>
</div>
</dialog>
</div>
JS
var isCaptionUpdate = false;
function captionUpdate(){
isCaptionUpdate = true;
};
var manualUploaderSection1 = new qq.s3.FineUploader({
element: document.getElementById('fine-uploader-manual-trigger-section1'),
template: 'qq-template-manual-trigger-section1',
autoUpload: false,
debug: true,
request: {
endpoint: "http://xx_my_bucket_xx.s3.amazonaws.com",
accessKey: "AKIAIAABIA",
},
signature: {
endpoint: "http://localhost/app/ci/php-s3-server/endpoint-cors.php"
},
uploadSuccess: {
endpoint: "http://localhost/app/ci/php-s3-server/endpoint-cors.php?success",
params: {
isBrowserPreviewCapable: qq.supportedFeatures.imagePreviews
}
},
session: {
endpoint: "http://localhost/app/ci/php-s3-server/endpoint-cors.php?filelist"
},
iframeSupport: {
localBlankPagePath: "success.html"
},
cors: {
expected: true
},
chunking: {
enabled: true
},
resume: {
enabled: true
},
deleteFile: {
enabled: true,
method: "POST",
endpoint: "http://localhost/app/ci/php-s3-server/endpoint-cors.php",
params: {
caption: function() {
if (isCaptionUpdate === true) {
isCaptionUpdate = false;
return document.getElementById('caption').value;
}
}
}
},
validation: {
itemLimit: 5,
sizeLimit: 15000000
},
thumbnails: {
placeholders: {
notAvailablePath: "http://localhost/app/ci/s3.fine-uploader/placeholders/not_available-generic.png",
waitingPath: "http://localhost/app/ci/s3.fine-uploader/placeholders/waiting-generic.png"
}
},
callbacks: {
onComplete: function(id, name, response) {
var previewLink = qq(this.getItemByFileId(id)).getByClass('preview-link')[0];
if (response.success) {
previewLink.setAttribute("href", response.tempLink)
}
},
onUpload: function(id, fileName) {
var caption = document.getElementById('caption').value;
this.setParams({'caption':caption});
}
}
});
qq(document.getElementById("trigger-upload-section1")).attach("click", function() {
manualUploaderSection1.uploadStoredFiles();
});
Server side code:
require '/vendor/autoload.php';
use Aws\S3\S3Client;
$clientPrivateKey = 'LB7r54Rgh9sCuTAC8V5F';
$serverPublicKey = 'AKIAU2ZEQ';
$serverPrivateKey = '8Xu6lxcDfKifHfn4pdELnM1E';
$expectedBucketName = 'xx_my_bucket_xx';
$expectedHostName = 'http://s3.amazonaws.com'; // v4-only
$expectedMaxSize = 15000000;
$method = getRequestMethod();
// This first conditional will only ever evaluate to true in a
// CORS environment
if ($method == 'OPTIONS') {
handlePreflight();
}
// This second conditional will only ever evaluate to true if
// the delete file feature is enabled
else if ($method == "DELETE") {
handleCorsRequest();
if (isset($_REQUEST['caption'])) {
updateObjectWithCaption();
} else {
deleteObject();
}
}
// This is all you really need if not using the delete file feature
// and not working in a CORS environment
else if ($method == 'POST') {
handleCorsRequest();
// Assumes the successEndpoint has a parameter of "success" associated with it,
// to allow the server to differentiate between a successEndpoint request
// and other POST requests (all requests are sent to the same endpoint in this example).
// This condition is not needed if you don't require a callback on upload success.
if (isset($_REQUEST["success"])) {
verifyFileInS3(shouldIncludeThumbnail());
}
else {
signRequest();
}
}
//filelist - this is to list already uploaded files
else if ($method == 'GET') {
if (isset($_REQUEST["filelist"])) {
getFileList('test/');
}
}
function getFileList($filePrefix) {
global $expectedBucketName;
$objects = getS3Client()->getIterator('ListObjects', array(
//$objects = getS3Client()->ListObjects(array(
'Bucket' => $expectedBucketName,
'Prefix' => $filePrefix //must have the trailing forward slash "/"
));
$object_list = array();
foreach ($objects as $object) {
//echo $object['Key'] . "<br>";
$object_metadata = getHeadObject($expectedBucketName, $object['Key']);
if (isset($object_metadata['Metadata']['qqfilename'])) {
$keyArr = explode("/", $object['Key']);
$posOfLastString = sizeof($keyArr) - 1;
$uuidArry = explode(".", $keyArr[$posOfLastString]);
$link = getTempLink($expectedBucketName, $object['Key']);
$object_new = array();
$object_new['name'] = $object_metadata['Metadata']['qqfilename'];
$object_new['uuid'] = $uuidArry[0];
$object_new['s3Key'] = $object['Key'];
$object_new['size'] = $object['Size'];
$object_new['s3Bucket'] = $expectedBucketName;
$object_new['thumbnailUrl'] = $link;
array_push($object_list, (object)$object_new);
}
}
echo json_encode($object_list);
}
// This will retrieve the "intended" request method. Normally, this is the
// actual method of the request. Sometimes, though, the intended request method
// must be hidden in the parameters of the request. For example, when attempting to
// send a DELETE request in a cross-origin environment in IE9 or older, it is not
// possible to send a DELETE request. So, we send a POST with the intended method,
// DELETE, in a "_method" parameter.
function getRequestMethod() {
global $HTTP_RAW_POST_DATA;
// This should only evaluate to true if the Content-Type is undefined
// or unrecognized, such as when XDomainRequest has been used to
// send the request.
if(isset($HTTP_RAW_POST_DATA)) {
parse_str($HTTP_RAW_POST_DATA, $_POST);
}
if (isset($_REQUEST['_method'])) {
return $_REQUEST['_method'];
}
return $_SERVER['REQUEST_METHOD'];
}
// Only needed in cross-origin setups
function handleCorsRequest()
// If you are relying on CORS, you will need to adjust the allowed domain here.
header('Access-Control-Allow-Origin: http://localhost');
}
// Only needed in cross-origin setups
function handlePreflight() {
handleCorsRequest();
header('Access-Control-Allow-Methods: POST');
header('Access-Control-Allow-Headers: Content-Type');
}
function getS3Client() {
global $serverPublicKey, $serverPrivateKey;
return S3Client::factory(array(
'key' => $serverPublicKey,
'secret' => $serverPrivateKey
));
}
// Only needed if the delete file feature is enabled
function deleteObject() {
getS3Client()->deleteObject(array(
'Bucket' => $_REQUEST['bucket'],
'Key' => $_REQUEST['key']
));
}
function getHeadObject($bucket, $key) {
$object_metadata = getS3Client()->headObject(array('Bucket' => $bucket,'Key' => $key));
$object_metadata = $object_metadata->toArray();
return $object_metadata;
}
function updateObjectWithCaption() {
$bucket = $_REQUEST['bucket'];
$key = $_REQUEST['key'];
$caption = $_REQUEST['caption'];
$object_metadata = getHeadObject($bucket, $key);
$filename = $object_metadata['Metadata']['qqfilename'];
$fileType = getFileType($key);
getS3Client()->copyObject(array(
'Bucket' => $bucket,
'Key' => $key,
'CopySource' => urlencode($_REQUEST['bucket'] . '/' . $key),
'MetadataDirective' => 'REPLACE',
//'CacheControl' => 'max-age=31536000',
//'Expires' => gmdate('D, d M Y H:i:s T', strtotime('+1 years')), // Set EXPIRES and CACHE-CONTROL headers to +1 year (RFC guidelines max.)
'ContentType' => $fileType,
'Metadata'=>array(
'qqcaption' => $caption,
'qqfilename' => $filename,
),
));
}
function getFileType($key) {
$file_parts = pathinfo($key);
$filetype = "";
switch($file_parts['extension'])
{
case "jpg":
$filetype = "image/jpeg";
break;
case "jpeg":
$filetype = "image/jpeg";
break;
case "png":
$filetype = "image/png";
break;
case "gif":
$filetype = "image/gif";
break;
case "tif":
$filetype = "image/tiff";
break;
case "tiff":
$filetype = "image/tiff";
break;
case "bmp":
$filetype = "image/bmp";
break;
}
return $filetype;
}
function signRequest() {
header('Content-Type: application/json');
$responseBody = file_get_contents('php://input');
$contentAsObject = json_decode($responseBody, true);
$jsonContent = json_encode($contentAsObject);
if (!empty($contentAsObject["headers"])) {
signRestRequest($contentAsObject["headers"]);
}
else {
signPolicy($jsonContent);
}
}
function signRestRequest($headersStr) {
$version = isset($_REQUEST["v4"]) ? 4 : 2;
if (isValidRestRequest($headersStr, $version)) {
if ($version == 4) {
$response = array('signature' => signV4RestRequest($headersStr));
}
else {
$response = array('signature' => sign($headersStr));
}
echo json_encode($response);
}
else {
echo json_encode(array("invalid" => true));
}
}
function isValidRestRequest($headersStr, $version) {
if ($version == 2) {
global $expectedBucketName;
$pattern = "/\/$expectedBucketName\/.+$/";
}
else {
global $expectedHostName;
$pattern = "/host:$expectedHostName/";
}
preg_match($pattern, $headersStr, $matches);
return count($matches) > 0;
}
function signPolicy($policyStr) {
$policyObj = json_decode($policyStr, true);
if (isPolicyValid($policyObj)) {
$encodedPolicy = base64_encode($policyStr);
if (isset($_REQUEST["v4"])) {
$response = array('policy' => $encodedPolicy, 'signature' => signV4Policy($encodedPolicy, $policyObj));
}
else {
$response = array('policy' => $encodedPolicy, 'signature' => sign($encodedPolicy));
}
echo json_encode($response);
}
else {
echo json_encode(array("invalid" => true));
}
}
function isPolicyValid($policy) {
global $expectedMaxSize, $expectedBucketName;
$conditions = $policy["conditions"];
$bucket = null;
$parsedMaxSize = null;
for ($i = 0; $i < count($conditions); ++$i) {
$condition = $conditions[$i];
if (isset($condition["bucket"])) {
$bucket = $condition["bucket"];
}
else if (isset($condition[0]) && $condition[0] == "content-length-range") {
$parsedMaxSize = $condition[2];
}
}
return $bucket == $expectedBucketName && $parsedMaxSize == (string)$expectedMaxSize;
}
function sign($stringToSign) {
global $clientPrivateKey;
return base64_encode(hash_hmac(
'sha1',
$stringToSign,
$clientPrivateKey,
true
));
}
function signV4Policy($stringToSign, $policyObj) {
global $clientPrivateKey;
foreach ($policyObj["conditions"] as $condition) {
if (isset($condition["x-amz-credential"])) {
$credentialCondition = $condition["x-amz-credential"];
}
}
$pattern = "/.+\/(.+)\\/(.+)\/s3\/aws4_request/";
preg_match($pattern, $credentialCondition, $matches);
$dateKey = hash_hmac('sha256', $matches[1], 'AWS4' . $clientPrivateKey, true);
$dateRegionKey = hash_hmac('sha256', $matches[2], $dateKey, true);
$dateRegionServiceKey = hash_hmac('sha256', 's3', $dateRegionKey, true);
$signingKey = hash_hmac('sha256', 'aws4_request', $dateRegionServiceKey, true);
return hash_hmac('sha256', $stringToSign, $signingKey);
}
function signV4RestRequest($rawStringToSign) {
global $clientPrivateKey;
$pattern = "/.+\\n.+\\n(\\d+)\/(.+)\/s3\/aws4_request\\n(.+)/s";
preg_match($pattern, $rawStringToSign, $matches);
$hashedCanonicalRequest = hash('sha256', $matches[3]);
$stringToSign = preg_replace("/^(.+)\/s3\/aws4_request\\n.+$/s", '$1/s3/aws4_request'."\n".$hashedCanonicalRequest, $rawStringToSign);
$dateKey = hash_hmac('sha256', $matches[1], 'AWS4' . $clientPrivateKey, true);
$dateRegionKey = hash_hmac('sha256', $matches[2], $dateKey, true);
$dateRegionServiceKey = hash_hmac('sha256', 's3', $dateRegionKey, true);
$signingKey = hash_hmac('sha256', 'aws4_request', $dateRegionServiceKey, true);
return hash_hmac('sha256', $stringToSign, $signingKey);
}
// This is not needed if you don't require a callback on upload success.
function verifyFileInS3($includeThumbnail) {
global $expectedMaxSize;
$bucket = $_REQUEST["bucket"];
$key = $_REQUEST["key"];
// If utilizing CORS, we return a 200 response with the error message in the body
// to ensure Fine Uploader can parse the error message in IE9 and IE8,
// since XDomainRequest is used on those browsers for CORS requests. XDomainRequest
// does not allow access to the response body for non-success responses.
if (isset($expectedMaxSize) && getObjectSize($bucket, $key) > $expectedMaxSize) {
// You can safely uncomment this next line if you are not depending on CORS
header("HTTP/1.0 500 Internal Server Error");
deleteObject();
echo json_encode(array("error" => "File is too big!", "preventRetry" => true));
}
else {
$link = getTempLink($bucket, $key);
$response = array("tempLink" => $link);
if ($includeThumbnail) {
$response["thumbnailUrl"] = $link;
}
echo json_encode($response);
}
}
// Provide a time-bombed public link to the file.
function getTempLink($bucket, $key) {
$client = getS3Client();
$url = "{$bucket}/{$key}";
$request = $client->get($url);
return $client->createPresignedUrl($request, '+15 minutes');
}
function getObjectSize($bucket, $key) {
$objInfo = getS3Client()->headObject(array(
'Bucket' => $bucket,
'Key' => $key
));
return $objInfo['ContentLength'];
}
// Return true if it's likely that the associate file is natively
// viewable in a browser. For simplicity, just uses the file extension
// to make this determination, along with an array of extensions that one
// would expect all supported browsers are able to render natively.
function isFileViewableImage($filename) {
$ext = strtolower(pathinfo($filename, PATHINFO_EXTENSION));
$viewableExtensions = array("jpeg", "jpg", "gif", "png", "tif", "tiff");
return in_array($ext, $viewableExtensions);
}
// Returns true if we should attempt to include a link
// to a thumbnail in the uploadSuccess response. In it's simplest form
// (which is our goal here - keep it simple) we only include a link to
// a viewable image and only if the browser is not capable of generating a client-side preview.
function shouldIncludeThumbnail() {
$filename = $_REQUEST["name"];
$isPreviewCapable = $_REQUEST["isBrowserPreviewCapable"] == "true";
$isFileViewableImage = isFileViewableImage($filename);
return !$isPreviewCapable && $isFileViewableImage;
}
When user click on 'Update Caption', it follows DELETE steps and since I am passing Caption param, it updates S3 file. But problem is in the file list, I will see a status text called 'Deleting.....' appears for brief time. How can I change status to 'Updating Caption....' or something similar
There are various text options you can set for the delete file feature, such as deleteFile.deletingStatusText.
As you can see in the deleteFile section of JS, caption is taken from document.getElementById('caption').value; that means, even if I click 'Update Caption' of 2nd or 3rd or 4th files, it is taking first occurrence of Caption element. How can I get the caption of the specific file ?
Your markup/template is flawed in that you will end up with multiple elements with an ID of "caption". This is not allowed in HTML. You'll need to restructure your markup accordingly. An ID is not appropriate here. Instead, use a class. You can always get the container element for a file using Fine Uploader's getItemByFileId API method. With this, you can query the descendant elements to look for one with a specific attribute.
Last but not least, how can I show 'Update Caption' button only for previously uploaded file. I do not want show this button on fresh upload.
Files submitted by the user (non-canned/initial files) will result in a call to your onSubmitted callback handler after they are represented in the DOM. At this point, you can use the previously mentioned getItemByFileId to retrieve the container element and hide the button.

MYSQL Error, what did i do wrong?

If I remove the or die("MySQL ERROR: ".mysqli_error()); from the code below, it gives me no error. But it also doesn't write to the database.
What am I doing wrong?
ob_start();
session_start();
require ('openid.php');
function logoutbutton() {
echo "<form action=\"steamauth/logout.php\" method=\"post\"><input value=\"Logout\" type=\"submit\" /></form>"; //logout button
}
function steamlogin() {
try {
require("steamauth/settings.php");
$openid = new LightOpenID($steamauth['domainname']);
$button['small'] = "small";
$button['large_no'] = "large_noborder";
$button['large'] = "large_border";
$button = $button[$steamauth['buttonstyle']];
if(!$openid->mode) {
if(isset($_GET['login'])) {
$openid->identity = 'http://steamcommunity.com/openid';
header('Location: ' . $openid->authUrl());
}
//echo "<form action=\"?login\" method=\"post\"> <input type=\"image\" src=\"http://cdn.steamcommunity.com/public/images/signinthroughsteam/sits_".$button.".png\"></form>";
} elseif($openid->mode == 'cancel') {
echo 'User has canceled authentication!';
} else {
if($openid->validate()) {
$id = $openid->identity;
$ptn = "/^http:\/\/steamcommunity\.com\/openid\/id\/(7[0-9]{15,25}+)$/";
preg_match($ptn, $id, $matches);
$_SESSION['steamid'] = $matches[1];
include_once("set.php");
$query = mysqli_query("SELECT * FROM users WHERE steamid='".$_SESSION['steamid']."'");
if (mysqli_num_rows($query) == 0) {
mysqli_query("INSERT INTO users (steamid) VALUES ('".$_SESSION['steamid']."')") or die("MySQL ERROR: ".mysqli_error());
}
if (isset($steamauth['loginpage'])) {
header('Location: '.$steamauth['loginpage']);
}
} else {
echo "User is not logged in.\n";
}
}
} catch(ErrorException $e) {
echo $e->getMessage();
}
}
Here's a screen-shot of my database structure:

Amazon Product Ads, is there an API to search for Categories?

I'm building a module that will help seller put their products catalogue in the Amazon Product Ads service. For that, I need to make a mapping between the client's category and the Amazon Product Ads categories.
Problem is, I can't find an API that will help me search for Categories, or a file containing all the existing categories for Amazon Product Ads.
I found that link http://docs.aws.amazon.com/AWSECommerceService/latest/DG/BrowseNodeIDs.html, that may be a start, but based on their API, it's not possible to search by text (like "Apparel") but by NodeId, which is not what I'm looking for :/
Can anyone of you help me please?
Thank you for your help :)
You have to use Browse Node Id of parent categories and bases on that you can search for sub categories.
Create a file named amazon_api_class.php
<?php
require_once 'aws_signed_request.php';
class AmazonProductAPI
{
/**
* Your Amazon Access Key Id
* #access private
* #var string
*/
private $public_key = "";
/**
* Your Amazon Secret Access Key
* #access private
* #var string
*/
private $private_key = "";
private $media_type = "";
private $region = "";
private $out_file_fp = "";
public function __construct($public, $private, $region) {
$this->public_key = $public;
$this->private_key = $private;
$this->region = $region;
}
public function getNode($node)
{
$parameters = array("Operation" => "BrowseNodeLookup",
"BrowseNodeId" => $node,
"ResponseGroup" => "BrowseNodeInfo");
$xml_response = aws_signed_request($parameters,
$this->public_key,
$this->private_key,
$this->region);
return ($xml_response);
}
public function setMedia($media, $file = "") {
$media_type = array("display", "csv");
if(!in_array($media,$media_type)) {
throw new Exception("Invalid Media Type");
exit();
}
$this->media_type = $media;
if($media == "csv") {
$this->out_file_fp = fopen($file,'a+');
}
}
private function writeOut($level, $name, $id, $parent) {
if($this->media_type == "display") {
$spaces = str_repeat( ' ', ( $level * 6 ) );
echo $spaces . $parent . ' : ' . $name . ' : ' . $id . "\n";
} elseif ($this->media_type == "csv") {
$csv_line = '"' . $parent . '","' . $name . '","' . $id . '"' . "\n";
fputs($this->out_file_fp, $csv_line);
} else {
throw new Exception("Invalid Media Type");
exit();
}
}
public function getBrowseNodes($nodeValue, $level = 0)
{
try {
$result = $this->getNode($nodeValue);
}
catch(Exception $e) {
echo $e->getMessage();
}
if(!isset($result->BrowseNodes->BrowseNode->Children->BrowseNode)) return;
if(count($result->BrowseNodes->BrowseNode->Children->BrowseNode) > 0) {
foreach($result->BrowseNodes->BrowseNode->Children->BrowseNode as $node) {
$this->writeOut($level, $node->Name,
$node->BrowseNodeId,
$result->BrowseNodes->BrowseNode->Name);
$this->getBrowseNodes($node->BrowseNodeId, $level+1);
}
} else {
return;
}
}
public function getNodeName($nodeValue)
{
try {
$result = $this->getNode($nodeValue);
}
catch(Exception $e) {
echo $e->getMessage();
}
if(!isset($result->BrowseNodes->BrowseNode->Name)) return;
return (string)$result->BrowseNodes->BrowseNode->Name;
}
public function getParentNode($nodeValue)
{
try {
$result = $this->getNode($nodeValue);
}
catch(Exception $e) {
echo $e->getMessage();
}
if(!isset($result->BrowseNodes->BrowseNode->Ancestors->BrowseNode->BrowseNodeId)) return;
$parent_node = array("id" => (string)$result->BrowseNodes->BrowseNode->Ancestors->BrowseNode->BrowseNodeId,
"name" => (string)$result->BrowseNodes->BrowseNode->Ancestors->BrowseNode->Name);
return $parent_node;
}}?>
Create file named as aws_signed_request.php
<?php
function aws_signed_request($params,$public_key,$private_key,$region)
{
$method = "GET";
$host = "ecs.amazonaws.".$region; // must be in small case
$uri = "/onca/xml";
$params["Service"] = "AWSECommerceService";
$params["AWSAccessKeyId"] = $public_key;
$params["AssociateTag"] = 'YOUR-ASSOCIATES-ID-HERE';
$params["Timestamp"] = gmdate("Y-m-d\TH:i:s\Z");
$params["Version"] = "2009-03-31";
/* The params need to be sorted by the key, as Amazon does this at
their end and then generates the hash of the same. If the params
are not in order then the generated hash will be different thus
failing the authetication process.
*/
ksort($params);
$canonicalized_query = array();
foreach ($params as $param=>$value)
{
$param = str_replace("%7E", "~", rawurlencode($param));
$value = str_replace("%7E", "~", rawurlencode($value));
$canonicalized_query[] = $param."=".$value;
}
$canonicalized_query = implode("&", $canonicalized_query);
$string_to_sign = $method."\n".$host."\n".$uri."\n".$canonicalized_query;
/* calculate the signature using HMAC with SHA256 and base64-encoding.
The 'hash_hmac' function is only available from PHP 5 >= 5.1.2.
*/
$signature = base64_encode(hash_hmac("sha256", $string_to_sign, $private_key, True));
/* encode the signature for the request */
$signature = str_replace("%7E", "~", rawurlencode($signature));
/* create request */
$request = "http://".$host.$uri."?".$canonicalized_query."&Signature=".$signature;
/* I prefer using CURL */
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL,$request);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($ch, CURLOPT_TIMEOUT, 15);
curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, 0);
$xml_response = curl_exec($ch);
if ($xml_response === False)
{
return False;
}
else
{
/* parse XML */
$parsed_xml = #simplexml_load_string($xml_response);
return ($parsed_xml === False) ? False : $parsed_xml;
}
}
?>
Create file named as index.php
<?php
/* Example usage of the Amazon Product Advertising API */
include("amazon_api_class.php");
$public_key = "YOUR-AMAZON-PUBLIC-KEY";
$private_key = "YOUR-AMAZON-SECRET-KEY";
$region = "com"; // or "CA" or "DE" etc.
$obj = new AmazonProductAPI($public_key, $private_key, $region);
$obj->setMedia("display");
$obj->getBrowseNodes("1036592"); //Apparel US store
?>
Dont forget to update your public and private key in index.php

Form Validator for empty fields

Im having issues with form validation in an empty field. I've included code if there is an error in the php and really thought that would do the trick, but it still submits the form, regardless and redirects to a thank you page.
The form is on: http://www.softwaretestingconference.com/try/register.html
Here is the php:
<?php
$firstnameErr = $lastnameErr = $positionErr = $companynameErr = $address1Err = $postcodeErr = $countryErr = $emailErr = $numberErr = $elecErr = $howManyErr;
$favFruit = array();
$myemail = 'tina.harris#31media.co.uk';//<-----Put Your email address here.
if ($_SERVER["REQUEST_METHOD"] == "POST") {
if (empty($_POST["firstname"])) {
$firstnameErr = "Please provide your first name";
}
else {
$firstname = $_POST["firstname"];
}
if (empty($_POST["lastname"])) {
$lastnameErr = "Please provide your first name";
}
else {
$lastname = $_POST["lastname"];
}
if (empty($_POST["position"])) {
$positionErr = "Please state your job position";
}
else {
$position = $_POST["position"];
}
if (empty($_POST["companyname"])) {
$companynameErr = "Please state your company's name";
}
else {
$companyname = $_POST["companyname"];
}
if (empty($_POST["address1"])) {
$address1Err = "Please provide an address for your invoice";
}
else {
$address1 = $_POST["address1"];
}
if (empty($_POST['address2'])) {
}
else {
$address2 = $_POST['address2'];
}
if (empty($_POST["postcode"])) {
$postcodeErr = "Please provide a postocde for your invoice";
}
else {
$postcode1 = $_POST["postcode"];
}
if (empty($_POST["country"])) {
$countryErr = "Please provide your country for your invoice";
}
else {
$country = $_POST["country"];
}
if (empty($_POST["email"])) {
$emailErr = "Please provide your email address";
}
else {
$email = $_POST["email"];
}
if (empty($_POST["number"])) {
$numberErr = "Please provide your phone number";
}
else {
$number = $_POST["number"];
}
if (empty($_POST["elec"])) {
$elecErr = "Please provide an electronic signature";
}
else {
$elec = $_POST["elec"];
}
}
if( empty($errors))
{
$to = $myemail;
$email_subject = "NSTC booking: $name";
$email_body = "You have received a new booking from NSTC. ".
" Here are the details: \n Places1: $places1 \n Places2: $places2 \n Places3: $places3 \n Title: $title \n First name: $firstname \n Last name: $lastname \n Position: $position \n Company name: $companyname \n Address1: $address1 \n Address2: $address2 \n Email: $email \n Number: \n $number \n Elec: $elec \n ";
if(isset($_POST['formDoor'])){
if (is_array($_POST['formDoor'])) {
foreach($_POST['formDoor'] as $value){
$email_body .= $value;
}
} else {
$value = $_POST['formDoor'];
$email_body .= $value;
}
}
$headers = "From: $myemail\n";
$headers .= "Reply-To: $email_address";
mail($to,$email_subject,$email_body,$headers);
//redirect to the 'thank you' page
header('Location: register-thanks.html');
}
?>
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
<html>
<head>
<title>Contact form handler</title>
</head>
<body>
<!-- This page is displayed only if there is some error -->
<?php
echo nl2br($errors);
?>
</body>
</html>
Your problem is in the following line (My assumption):
if( empty($errors))
You are not setting anything in the $errors variable.
I would do as follows (I will give you one example, you then have to apply it to each one of your if statements.)
at the beginning of your script, define an empty array:
$errors = array();
and then (this is what you will have to replicate in all your "if" statements:
if (empty($_POST["email"])) {
$errors['mailError'] = "Please provide your email address";
}
else {
$email = $_POST["email"];
}
and at the end of your script:
if (count($errors) === 0) {
//passed, no errors.
} else {
//there are errors. handle them.
}