2

When an iOS app connects to a json based php web api using afnetworking, what is the correct path to use to store photos for this php function?

When trying to call the upload php function from api.php the app shows a json error via uialert view

//upload API
function upload($id, $photoData, $title) {

// index.php passes as first parameter to this function $_SESSION['IdUser']
// $_SESSION['IdUser'] should contain the user id, if the user has already been authorized
// remember? you store the user id there in the login function
if (!$id) errorJson('Authorization required');

// check if there was no error during the file upload
if ($photoData['error']==0) {

    // insert the details about the photo to the "photos" table
    $result = query("INSERT INTO photos(IdUser,title) VALUES('%d','%s')", $id, $title, $token);
    if (!$result['error']) {

        // fetch the active connection to the database (it's initialized automatically in lib.php)
        global $link;
     
        // get the last automatically generated ID in the photos table
        $IdPhoto = mysqli_insert_id($link);
     
        // move the temporarily stored file to a convenient location
        // your photo is automatically saved by PHP in a temp folder
        // you need to move it over yourself to your own "upload" folder
        if (move_uploaded_file($photoData['tmp_name'], "upload/".$IdPhoto.".jpg")) {

            // file moved, all good, generate thumbnail
            thumb("upload/".$IdPhoto.".jpg", 180);
            
            //just print out confirmation to the iPhone app
            print json_encode(array('successful'=>1));
        } else {
            //print out an error message to the iPhone app
            errorJson('Upload on server problem');
        };

    } else {
        errorJson('Hmm...Upload database problem.'.$result['error']);
    }
} else {
    errorJson('Upload malfunction');
}
} 

the original author of the api quotes

 If you set up a custom domain for this tutorial, and the API files are in the root of the 
 domain instead of being inside a sub-folder, set the path to an empty string.

The api files have been placed in the following path on a lamp server using the company linode as a host var/www/html/. So far the register and login functions work when called from the app.

#define kAPIHost @"http://104.237.123.187/" #define kAPIPath @""

When testing on a Mamp server locally, the path for kAPIHost and kAPIPath were

#define kAPIHost @"http://localhost:8888"
#define kAPIPath @"iReporter/" 

The .jpg files were stored in a folder named upload that was in the iReporter folder thats hosted at localhost:888 in htdocs: Htdocs > iReporter > Upload.

When hosting the web api, the only way connection would work was putting the main files the app connects to in var/www/html/. I tried putting the upload folder in the same path but am receiving the appropriate UIAlert at runtime expressing the json error that there was an uploading malfunction.

What is the proper way to host this function?

//Entire api.php file
<?php
// helper function, which outputs error messages in JSON format
// so that the iPhone app can read them
// the function just takes in a dictionary with one key "error" and 
// encodes it in JSON, then prints it out and then exits the program
function errorJson($msg){
print json_encode(array('error'=>$msg));
exit();
}

// register API
function register($user, $pass) {

//check if username exists in the database (inside the "login" table)
$login = query("SELECT username FROM login WHERE username='%s' limit 1", $user);

if (count($login['result'])>0) {

    //the username exists, return error to the iPhone app
    errorJson('Username already exists');
}

//try to insert a new row in the "login" table with the given username and password
$result = query("INSERT INTO login(username, pass) VALUES('%s','%s')", $user, $pass);

if (!$result['error']) {
    //registration is susccessfull, try to also directly login the new user
    login($user, $pass);
} else {
    //for some database reason the registration is unsuccessfull
    errorJson('Registration failed');
}

}

//login API
function login($user, $pass) {

// try to match a row in the "login" table for the given username and password
$result = query("SELECT IdUser, username FROM login WHERE username='%s' AND pass='%s' limit 1", $user, $pass);

if (count($result['result'])>0) {
    // a row was found in the database for username/pass combination
    // save a simple flag in the user session, so the server remembers that the user is authorized
    $_SESSION['IdUser'] = $result['result'][0]['IdUser'];
    
    // print out the JSON of the user data to the iPhone app; it looks like this:
    // {IdUser:1, username: "Name"}
    print json_encode($result);
} else {
    // no matching username/password was found in the login table
    errorJson('Authorization failed');
}

}

//upload API
function upload($id, $photoData, $title) {

// index.php passes as first parameter to this function $_SESSION['IdUser']
// $_SESSION['IdUser'] should contain the user id, if the user has already been authorized
// remember? you store the user id there in the login function
if (!$id) errorJson('Authorization required');

// check if there was no error during the file upload
if ($photoData['error']==0) {

    // insert the details about the photo to the "photos" table

    //1. change ok
    $result = query("INSERT INTO photos(IdUser,title) VALUES('%d','%s')", $id, $title);
    if (!$result['error']) {

        // fetch the active connection to the database (it's initialized automatically in lib.php)
        global $link;
     
        // get the last automatically generated ID in the photos table
        $IdPhoto = mysqli_insert_id($link);
     
        // move the temporarily stored file to a convenient location
        // your photo is automatically saved by PHP in a temp folder
        // you need to move it over yourself to your own "upload" folder
        if (move_uploaded_file($photoData['tmp_name'], "upload/".$IdPhoto.".jpg")) {

            // file moved, all good, generate thumbnail
            thumb("upload/".$IdPhoto.".jpg", 180);
            
            //just print out confirmation to the iPhone app
            print json_encode(array('successful'=>1));
        } else {
            //print out an error message to the iPhone app
            errorJson('Upload on server problem');
        };

    } else {
        errorJson('Hmm...Upload database problem.'.$result['error']);
    }
} else {
    errorJson('Upload malfunction');
}
}

//logout API
function logout() {

// by saving an empty array to $_SESSION you are
// effectively destroying all the user session data
// ie. the server won't "remember" anymore anything about
// the current user
$_SESSION = array();

// and to make double-sure, there's also a built-in function 
// which wipes out the user session
session_destroy();
}

//stream API
//
// there are 2 ways to use the function:
// 1) don't pass any parameters - then the function will fetch all photos from the database
// 2) pass a photo id as a parameter - then the function will fetch the data of the requested photo
//
// Q: what "$IdPhoto=0" means? A: It's the PHP way to say "first param of the function is $IdPhoto, 
// if there's no param sent to the function - initialize $IdPhoto with a default value of 0"
function stream($IdPhoto=0) {

if ($IdPhoto==0) {

    // load the last 50 photos from the "photos" table, also join the "login" so that you can fetch the 
    // usernames of the photos' authors
    $result = query("SELECT IdPhoto, title, l.IdUser, username FROM photos p JOIN login l ON (l.IdUser = p.IdUser) ORDER BY IdPhoto DESC LIMIT 50");

} else {
    //do the same as above, but just for the photo with the given id
    $result = query("SELECT IdPhoto, title, l.IdUser, username FROM photos p JOIN login l ON (l.IdUser = p.IdUser) WHERE p.IdPhoto='%d' LIMIT 1", $IdPhoto);
}

if (!$result['error']) {
    // if no error occured, print out the JSON data of the 
    // fetched photo data
    print json_encode($result);
} else {
    //there was an error, print out to the iPhone app
    errorJson('Photo stream is broken');
}
}

Edit

Here is some s\console output

[24-Jul-2020 11:22:06 America/Los_Angeles] PHP Warning:  
 move_uploaded_file(upload/24.jpg): failed to open stream: Permission 
denied in /var/www/html/api.php on line 81
[24-Jul-2020 11:22:06 America/Los_Angeles] PHP Warning:  
move_uploaded_file(): Unable to move '/tmp/phpjbpfcx' to 'upload/24.jpg' in /var/www/html/api.php on line 81

enter image description here

john smith
  • 73
  • 1
  • 7
  • 1
    **Warning:** Your code is vulnerable to SQL Injection attacks. You should use parameterised queries and prepared statements to help prevent attackers from compromising your database by using malicious input values. http://bobby-tables.com gives an explanation of the risks, as well as some examples of how to write your queries safely using PHP / mysqli. **Never** insert unsanitised data directly into your SQL. The way your code is written now, someone could easily steal, incorrectly change, or even delete your data. – ADyson Jul 24 '20 at 09:31
  • 1
    https://phpdelusions.net/mysqli also contains good examples of writing safe SQL using mysqli. Parameterising your queries will also greatly reduce the risk of accidental syntax errors as a result of un-escaped input values. – ADyson Jul 24 '20 at 09:31
  • 1
    Anyway, which error are you seeing exactly? Is it this one: `errorJson('Upload on server problem');` ? Please be specific. And, if you're seeing that, have you tried to investigate _why_ that's happening? e.g. have you got PHP set to log errors and warnings so that you can check if you've got, for example, a permission problem? In theory you could use any folder you like to store the images. You should just need to make sure the path is correct and that PHP has permission to write to it. We can't see either of those things just from the code, and you provided no debugging info. – ADyson Jul 24 '20 at 09:34
  • Yes, it's showing the `errorJson('Upload on server problem');` error. – john smith Jul 24 '20 at 16:52
  • Thank you for your response. I'll try viewing the error logs today. – john smith Jul 24 '20 at 16:52
  • @ADyson thank you for your response. After checking `error.log` some of the output includes `[24-Jul-2020 11:22:06 America/Los_Angeles] PHP Warning: move_uploaded_file(upload/24.jpg): failed to open stream: Permission denied in /var/www/html/api.php on line 81 [24-Jul-2020 11:22:06 America/Los_Angeles] PHP Warning: move_uploaded_file(): Unable to move '/tmp/phpjbpfcx' to 'upload/24.jpg' in /var/www/html/api.php on line 81 ` – john smith Jul 24 '20 at 18:56
  • I have a feeling these two lines should be edited to the server path `if (move_uploaded_file($photoData['tmp_name'], "upload/".$IdPhoto.".jpg")) { // file moved, all good, generate thumbnail thumb("upload/".$IdPhoto.".jpg", 180);` – john smith Jul 24 '20 at 20:15
  • going to take a peek at this here https://stackoverflow.com/questions/8103860/move-uploaded-file-gives-failed-to-open-stream-permission-denied-error – john smith Jul 24 '20 at 21:16

0 Answers0