Normal
Okay,I am ready for some criticism and feedback -Here is my overall structure:/ api / api.php/ api / models / volunteer.php/ api / security / authentication.phpHere is my Authentication File:[CODE]$realm = 'API'; $admins = array('REDACTED' => 'REDACTED', 'REDACTED2' => 'REDACTED2'); // function to parse the http auth header function http_digest_parse($txt) { // protect against missing data $needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1); $data = array(); $keys = implode('|', array_keys($needed_parts)); preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', $txt, $matches, PREG_SET_ORDER); foreach ($matches as $m) { $data[$m[1]] = $m[3] ? $m[3] : $m[4]; unset($needed_parts[$m[1]]); } return $needed_parts ? false : $data; } if (empty($_SERVER['PHP_AUTH_DIGEST'])) { header('HTTP/1.1 401 Unauthorized'); header('WWW-Authenticate: Digest realm="'.$realm. '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); print "Sorry, you are not authorized to access this area"; exit; } // analyze the PHP_AUTH_DIGEST variable if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) || !isset($admins[$data['username']])) { header('HTTP/1.1 401 Unauthorized'); header('WWW-Authenticate: Digest realm="'.$realm. '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); print "Sorry, you are not authorized to access this area"; exit; } // generate the valid response $A1 = md5($data['username'] . ':' . $realm . ':' . $admins[$data['username']]); $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']); $valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2); if ($data['response'] != $valid_response){ header('HTTP/1.1 401 Unauthorized'); header('WWW-Authenticate: Digest realm="'.$realm. '",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"'); print "Sorry, you are not authorized to access this area"; exit; }[/CODE]The authentication works great, I am utilizing Postman as [USER=1]@RastaLulz[/USER] mentioned and it really helps to test the system!Now for the API.php file:[CODE]<?php //Require Authentication require_once 'security/authentication.php'; header('Content-Type: application/json'); //Set return type to JSON define('IN_INDEX', 1); //Define access to allow global.php to be referenced //Include Global File include_once '../../global.php'; //Access global.php, which will give access to the engine which has the MySQL connection //Declare Global Variables global $engine; //Define engine from the global file //Include Model Files include_once 'models/volunteer.php'; //Include our volunteer model, which will give the blueprint / class for what a volunteer is //Declare Model Variables $volunteer = new Volunteer($engine); //Define an instance of our volunteer //Get the type of request, current working on just GET requests $reqType = ''; if(isset($_GET['type'])){ $reqType = $_GET['type']; }else{ header('HTTP/1.1 400 Bad Request'); print "Must Define Type Parameter"; exit; } switch(strtoupper($reqType)){ case "GET": { HandleGET(); //We established we want to GET, we can call this function to handle our GET options } break; case "POST": { HandlePOST(); } break; default: { header('HTTP/1.1 404 Not Found'); print "The requested Type is not supported"; exit; } break; } function HandleGET(){ global $volunteer; //Get access to our blueprint class //What is the action we want to GET $action = ''; if(isset($_GET['action'])){ $action = $_GET['action']; }else{ header('HTTP/1.1 400 Bad Request'); print "Must Define Action Parameter"; exit; } switch(strtoupper($action)){ case "VOLUNTEERS": //Sample for returning all of the volunteers in the system { //Volunteer Query $result = $volunteer->read(); $num = mysqli_num_rows($result); //Check Volunteers Exist if($num > 0){ // Volunteer Array $volunteers_arr = array(); $volunteers_arr['data'] = array(); while($row = mysqli_fetch_array($result)){ extract($row); $volunteer_item = array( 'id' => $ID, 'fname' => $fname, 'lname' => $lname, 'email' => $email, 'phone' => $phone, 'created' => $created ); //Push to "data" results array_push($volunteers_arr['data'], $volunteer_item); } //Turn result array to JSON echo json_encode($volunteers_arr); }else{ //No Posts echo json_encode( array('message' => 'No Volunteers Found') ); } } break; default: { header('HTTP/1.1 404 Not Found'); print "The requested Action is not supported"; exit; } break; } } function HandlePOST(){ global $volunteer; }?>[/CODE]And here is my basic volunteer model class:[CODE]<?phpclass Volunteer{ private $engine; private $table = 'volunteers'; //Post Properties public $ID; public $firstname; public $lastname; public $email; public $phone; public $account_create; // Constructor with DB public function __construct($dbEngine){ $this->engine = $dbEngine; } // Get Volunteers public function read(){ //Create Query $query = 'SELECT vol.ID as ID, vol.firstname as fname, vol.lastname as lname, vol.email as email, vol.phone as phone, vol.account_created as created FROM ' . $this->table . ' vol ORDER BY vol.account_created DESC'; //Fetch Results $results = $this->engine->query($query); return $results; }}?>[/CODE][automerge]1607790736[/automerge]Just going to bump this, as I am on a time frame and want to know if this is following best practices or if I should change how I am implementing this...
Okay,
I am ready for some criticism and feedback -
Here is my overall structure:
/ api / api.php
/ api / models / volunteer.php
/ api / security / authentication.php
Here is my Authentication File:
[CODE]$realm = 'API';
$admins = array('REDACTED' => 'REDACTED', 'REDACTED2' => 'REDACTED2');
// function to parse the http auth header
function http_digest_parse($txt)
{
// protect against missing data
$needed_parts = array('nonce'=>1, 'nc'=>1, 'cnonce'=>1, 'qop'=>1, 'username'=>1, 'uri'=>1, 'response'=>1);
$data = array();
$keys = implode('|', array_keys($needed_parts));
preg_match_all('@(' . $keys . ')=(?:([\'"])([^\2]+?)\2|([^\s,]+))@', $txt, $matches, PREG_SET_ORDER);
foreach ($matches as $m) {
$data[$m[1]] = $m[3] ? $m[3] : $m[4];
unset($needed_parts[$m[1]]);
}
return $needed_parts ? false : $data;
if (empty($_SERVER['PHP_AUTH_DIGEST'])) {
header('HTTP/1.1 401 Unauthorized');
header('WWW-Authenticate: Digest realm="'.$realm.
'",qop="auth",nonce="'.uniqid().'",opaque="'.md5($realm).'"');
print "Sorry, you are not authorized to access this area";
exit;
// analyze the PHP_AUTH_DIGEST variable
if (!($data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST'])) || !isset($admins[$data['username']]))
// generate the valid response
$A1 = md5($data['username'] . ':' . $realm . ':' . $admins[$data['username']]);
$A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);
$valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);
if ($data['response'] != $valid_response){
}[/CODE]
The authentication works great, I am utilizing Postman as [USER=1]@RastaLulz[/USER] mentioned and it really helps to test the system!
Now for the API.php file:
[CODE]<?php
//Require Authentication
require_once 'security/authentication.php';
header('Content-Type: application/json'); //Set return type to JSON
define('IN_INDEX', 1); //Define access to allow global.php to be referenced
//Include Global File
include_once '../../global.php'; //Access global.php, which will give access to the engine which has the MySQL connection
//Declare Global Variables
global $engine; //Define engine from the global file
//Include Model Files
include_once 'models/volunteer.php'; //Include our volunteer model, which will give the blueprint / class for what a volunteer is
//Declare Model Variables
$volunteer = new Volunteer($engine); //Define an instance of our volunteer
//Get the type of request, current working on just GET requests
$reqType = '';
if(isset($_GET['type'])){
$reqType = $_GET['type'];
}else{
header('HTTP/1.1 400 Bad Request');
print "Must Define Type Parameter";
switch(strtoupper($reqType)){
case "GET":
HandleGET(); //We established we want to GET, we can call this function to handle our GET options
break;
case "POST":
HandlePOST();
default:
header('HTTP/1.1 404 Not Found');
print "The requested Type is not supported";
function HandleGET(){
global $volunteer; //Get access to our blueprint class
//What is the action we want to GET
$action = '';
if(isset($_GET['action'])){
$action = $_GET['action'];
print "Must Define Action Parameter";
switch(strtoupper($action)){
case "VOLUNTEERS": //Sample for returning all of the volunteers in the system
//Volunteer Query
$result = $volunteer->read();
$num = mysqli_num_rows($result);
//Check Volunteers Exist
if($num > 0){
// Volunteer Array
$volunteers_arr = array();
$volunteers_arr['data'] = array();
while($row = mysqli_fetch_array($result)){
extract($row);
$volunteer_item = array(
'id' => $ID,
'fname' => $fname,
'lname' => $lname,
'email' => $email,
'phone' => $phone,
'created' => $created
);
//Push to "data" results
array_push($volunteers_arr['data'], $volunteer_item);
//Turn result array to JSON
echo json_encode($volunteers_arr);
//No Posts
echo json_encode(
array('message' => 'No Volunteers Found')
print "The requested Action is not supported";
function HandlePOST(){
global $volunteer;
?>[/CODE]
And here is my basic volunteer model class:
class Volunteer{
private $engine;
private $table = 'volunteers';
//Post Properties
public $ID;
public $firstname;
public $lastname;
public $email;
public $phone;
public $account_create;
// Constructor with DB
public function __construct($dbEngine){
$this->engine = $dbEngine;
// Get Volunteers
public function read(){
//Create Query
$query = 'SELECT
vol.ID as ID,
vol.firstname as fname,
vol.lastname as lname,
vol.email as email,
vol.phone as phone,
vol.account_created as created
FROM
' . $this->table . ' vol
ORDER BY
vol.account_created DESC';
//Fetch Results
$results = $this->engine->query($query);
return $results;
[automerge]1607790736[/automerge]
Just going to bump this, as I am on a time frame and want to know if this is following best practices or if I should change how I am implementing this...