Trying to upload an image and getting an error

Do you understand the workflow that you’re trying to do?

  1. Let the user select a picture from their camera roll.

  2. Copy that picture to system.TemporaryDirectory and name it based on whatever you have in the variable userName with a .jpg extension.

  3. Setup data to be sent to your web server using the multipart library

  4. Send the data using network.request()

  5. A script in your CGI-BIN folder on your web server receives the upload

  6. You potentially have to base64 decode the image file.

  7. in that script save the image to a folder on your web server (not your Corona app) that you have permissions to write the file to.

So when you say any jpg image in the sandbox, the answer is no. It can only send a file named after the value in userName with a .jpg extension. But your user can pick any photo out of their camera roll and save it to your sandbox. So from that perspective sure, but it will overwrite whatever userName.jpg is on the server so you will only have one file there.

The only one of those I am able to accomplish is letting the user select the photo from their camera role . When the user clicks on the picture it just goes back to the app and nothing happens . 

The app is an instagram like app which means they can upload as many pictures as they want, which is not what I am trying to do now . Now I am trying to let them upload one profile picture whenever they want .

This might get you closer to your goal if you want to check it out. I haven’t gotten the multipart form upload part to work, but the image is being saved to the sandbox ok and is ready to be uploaded:

[lua]

local photo – holds the photo object

local PHOTO_FUNCTION = media.PhotoLibrary – or media.SavedPhotosAlbum?

local tmpDirectory = system.TemporaryDirectory

local photoGroup

local localPhotoFileName=“test.jpg”

local btn_selectFromGallery


– prepare the image for upload by saving it to the sandbox temporary directory


local function prepImageForUpload()

     print( “saving”…localPhotoFileName )

     --save the image to the local app sandbox

     display.save(photoGroup, localPhotoFileName, tmpDirectory)

     print( “pic saved in temp directory, uploading now” )

     --finally upload the pic

     uploadPic()-- this would be your custom local function, needs work

end


– Executes after the user selects a pic from the gallery (or cancels)


local handleDoneSelectingPic= function(event)

     photo = event.target

     print(“done selecting pic”)

  

     if photo then

          print( “picSelected” )

          photoGroup = display.newGroup()

          --this shows it on the screen too

          photoGroup:insert(photo)

          photoGroup:scale(.3,.3)

          photoGroup.x = display.contentWidth/2

          photoGroup.y = display.contentWidth/2-100

          localPhotoFileName=“photoSelected”…math.random(100000, 999999)…".jpg"

          --save image after delay so that not in gallery picker and it has time to actually be rendered on the screen 

          timer.performWithDelay( 500, prepImageForUpload )   

     else

          print( “No Image Selected” )

     end

end


– btn handler that opens the gallery


local btn_selectFromGallery

local function selectFromGalleryBtn_handler( event )

     – Delay a bit to allow the display to display refresh before calling the Photo Picker, then open it

     timer.performWithDelay( 100, function() media.selectPhoto( { listener = handleDoneSelectingPic, mediaSource = PHOTO_FUNCTION } ) end )

     return true

end


— just the selectFromGallery button


btn_selectFromGallery=display.newImage(“images/btn_uploadPics.png”,centerX,450) 

    btn_selectFromGallery:addEventListener(“tap”, selectFromGalleryBtn_handler)

    sceneGroup:insert(btn_selectFromGallery)

[/lua]

I just tried this and it’s not working .

local composer = require( "composer" ) local scene = composer.newScene() local widget = require("widget") -- forward declare the text fields local json = require("json") local button local MultipartFormData = require("class\_MultipartFormData") local userName = composer.getVariable( "username" ) local function networkListener( event ) if ( event.isError ) then local alert = native.showAlert( "Error Loading .", "Check your internet connection .", { "Try again" } ) end end local photo -- holds the photo object local PHOTO\_FUNCTION = media.PhotoLibrary -- or media.SavedPhotosAlbum? local tmpDirectory = system.TemporaryDirectory local photoGroup local localPhotoFileName= userName .. ".jpg" local btn\_selectFromGallery ----------------------------------------------------------------------- -- prepare the image for upload by saving it to the sandbox temporary directory ----------------------------------------------------------------------- local function prepImageForUpload() print( "saving"..localPhotoFileName ) --save the image to the local app sandbox display.save(photoGroup, localPhotoFileName, tmpDirectory) print( "pic saved in temp directory, uploading now" ) --finally upload the pic uploadPic()-- this would be your custom local function, needs work end ----------------------------------------------------------------------- -- Executes after the user selects a pic from the gallery (or cancels) ----------------------------------------------------------------------- local handleDoneSelectingPic= function(event) photo = event.target print("done selecting pic") if photo then print( "picSelected" ) photoGroup = display.newGroup() --this shows it on the screen too photoGroup:insert(photo) photoGroup:scale(.3,.3) photoGroup.x = display.contentWidth/2 photoGroup.y = display.contentWidth/2-100 localPhotoFileName="photoSelected"..math.random(100000, 999999)..".jpg" --save image after delay so that not in gallery picker and it has time to actually be rendered on the screen timer.performWithDelay( 500, prepImageForUpload ) else print( "No Image Selected" ) end end ----------------------------------------------------------------------- -- btn handler that opens the gallery ----------------------------------------------------------------------- local btn\_selectFromGallery local function selectFromGalleryBtn\_handler( event ) -- Delay a bit to allow the display to display refresh before calling the Photo Picker, then open it timer.performWithDelay( 100, function() media.selectPhoto( { listener = handleDoneSelectingPic, mediaSource = PHOTO\_FUNCTION } ) end ) return true end function scene:create(event) local screenGroup = self.view local background = display.newImageRect("insta.jpg",display.contentWidth,display.contentHeight) background.x = display.contentCenterX background.y = display.contentCenterY screenGroup:insert(background) local passedInParams = event.params --\<------ important. This is how you get the passed values default = display.newImage( "default.jpg" ) -- position the image default:translate( 160, 75 ) default:scale( 0.12, 0.12 ) screenGroup:insert(default) local userNameText = display.newText(userName, 160, 200, native.systemFont, 30 ) userNameText:setFillColor( 1, 0, 0 ) screenGroup:insert(userNameText) btn\_selectFromGallery = widget.newButton( { shape = "roundedRect", left = 70, top = 350, id = "pfp", label = "Upload picture", onEvent = pickPhoto, fillColor = { default={ 1, 0.2, 0.5, 0.7 }, over={ 1, 0.2, 0.5, 1 } }, labelColor = { default={ 2, 4, 1.5 }, over={ 2, 5, 1.5, 2.2 } } } ) screenGroup:insert(btn\_selectFromGallery) end function scene:show(event) local phase = event.phase if ( phase == "will" ) then print("Phase started") elseif ( phase == "did" ) then print("phase on login") local tabBar = composer.getVariable("savedTabBar") tabBar.isVisible = true btn\_selectFromGallery:addEventListener("tap", selectFromGalleryBtn\_handler) end composer.removeScene( "login" ) end scene:addEventListener( "show" ) function scene:hide(event) local phase = event.phase if ( phase == "will" ) then print("Phase started") display.remove(button) elseif ( phase == "did" ) then print("phase on login") end end function scene:destroy(event) end scene:addEventListener("create", scene) scene:addEventListener("show", scene) scene:addEventListener("hide", scene) scene:addEventListener("destroy", scene) return scene

I don’t see any where in that code where you have an “uploadPic()” function in this code and you’ve been sharing code that would appear to be that function. At some point you have to call code that sets up your multipart mime code and call network.request().

Your other code never shows where you call uploadPic() so there is some disconnect there. 

You also have your button with two handlers.

 btn\_selectFromGallery = widget.newButton( { label = "Upload picture", onEvent = pickPhoto, } )

Note, for clarity, I removed important style code for the button so you can focus in on the onEvent line. That’s trying to call a function called pickPhoto() which I also don’t see. You should not be adding your own events to widget buttons, in other words get rid of this line:

btn\_selectFromGallery:addEventListener("tap", selectFromGalleryBtn\_handler)

and change your button code to:

 btn\_selectFromGallery = widget.newButton( { shape = "roundedRect", left = 70, top = 350, id = "pfp", label = "Upload picture", onRelease = selectFromGalleryBtn\_handler, --\<------- change this line to this. fillColor = { default={ 1, 0.2, 0.5, 0.7 }, over={ 1, 0.2, 0.5, 1 } }, labelColor = { default={ 2, 4, 1.5 }, over={ 2, 5, 1.5, 2.2 } } } )

But you still need to call your uploadPhoto() function which doesn’t seem to exist in the scene code above.

Rob

Yeah I was gonna add the uploadPic after I get the image in sandbox . 

Hello . I;m still having this problem . 

local function networkListener( event ) if ( event.isError ) then local alert = native.showAlert( "Error Loading .", "Check your internet connection .", { "Try again" } ) end end -- Selection completion listener local function onComplete( event ) local photo = event.target if photo then print( "photo w,h = " .. photo.width .. "," .. photo.height ) local multipart = MultipartFormData.new() local path=system.pathForFile( "bg1.png", system.TemporaryDirectory ) multipart:addFile("Image", path, "images/uploads", userName .. ".jpg") local params = {} params.body = multipart:getBody() params.headers = multipart:getHeaders() -- Headers not valid until getBody() is called. network.request("http://hash.host22.com/upload.php", "POST", networkListener, params) end end local function pickPhoto( event ) media.selectPhoto( { mediaSource = media.SavedPhotosAlbum, listener = onComplete, origin = button.contentBounds, permittedArrowDirections = { "right" }, destination = { baseDir=system.TemporaryDirectory, filename= userName .. ".jpg" } }) end

That’s my current code I don’t know what to do i’m stuck 

I don’t know what the multipart:add() is expecting, but this doesn’t look right to me:

 local path=system.pathForFile( "bg1.png", system.TemporaryDirectory ) multipart:addFile("Image", path, "images/uploads", userName .. ".jpg")

What is bg1.png? How does it get to system.TemporaryDirectory?  I think you probably want:

 local path=system.pathForFile( userName .. ".jpg", system.TemporaryDirectory ) multipart:addFile("Image", path, "images/uploads", userName .. ".jpg")

or something similar.

Rob

bg1.png is an image . The code you gave, is that to store the images in there ?

In your call to media.selectPhoto() you are saying to save a file named after the user’s userName as a .jpg file and put it in system.TemporaryDirectory:

destination = { baseDir=system.TemporaryDirectory, filename= userName .. ".jpg" } 

I don’t see where your app is generating a file named bg1.png, so it doesn’t make sense to me that would be a file you want to upload. Now I don’t have the source of documentation for the “multipart” library you are using. So I’m guessing at what parameters are needed but I expect you need an input file name and a file name to name it on the server.  I would also expect that on your server you want the person’s profile image named after their username as well.

So you need to figure out what bg1.png is and why you’re using it there or understand that you probably copy/pasted that from somewhere and you need to use the actual filename of the image selected by the user which is userName … “.jpg”.

Rob

My goal is to make the user put any picture as their profile picture not bg1.png

Did you try my suggestion?

I don’t even see bg1.png anymore . I just want to store the users photos to the system temporary file and then let them pick one as the profile pic.

I’m still having problems here . I have the app on my phone. When I click on the upload button I go to my gallery and select a picture . When I select the picture I go right back to the profile.lua screen and the image doesn’t get saved . Nothing happens .

 button = widget.newButton( { shape = "roundedRect", left = 70, top = 350, id = "pfp", label = "Upload picture", onEvent = pickPhoto, fillColor = { default={ 1, 0.2, 0.5, 0.7 }, over={ 1, 0.2, 0.5, 1 } }, labelColor = { default={ 2, 4, 1.5 }, over={ 2, 5, 1.5, 2.2 } } } ) screenGroup:insert(button)

local MultipartFormData = require("class\_MultipartFormData") -- Selection completion listener local function onComplete( event ) local photo = event.target if photo then print( "photo w,h = " .. photo.width .. "," .. photo.height ) local multipart = MultipartFormData.new() local path=system.pathForFile( userName .. ".jpg", system.TemporaryDirectory ) multipart:addFile("Image", path, "images/uploads", userName .. ".jpg") local params = {} params.body = multipart:getBody() params.headers = multipart:getHeaders() -- Headers not valid until getBody() is called. network.request("http://hash.host22.com/upload.php", "POST", networkListener, params) end end local function pickPhoto( event ) media.selectPhoto( { mediaSource = media.SavedPhotosAlbum, listener = onComplete, origin = button.contentBounds, permittedArrowDirections = { "right" }, destination = { baseDir=system.TemporaryDirectory, filename= userName .. ".jpg" } }) end

Again, I don’t know anything about the library you are using for the multipart mime extension. I can’t verify that you are passing the right parameters to the function.  Secondly, I don’t know the code of your upload.php script and if it works with how you are attempting to send the file.

Where did you get the multipart mime code?

Can you share your upload.php script?

Rob

upload.php:

ini\_set('display\_errors', 1); ini\_set('display\_startup\_errors', 1); error\_reporting(E\_ALL); $servername = "localhost"; $username = "id1662780\_btisson13"; $password = "bigman23"; $database = "id1662780\_hash"; $con = new mysqli($servername, $username, $password, $database); if($con == true) { } // Check connection if ($con-\>connect\_error) { die("Connection failed: " . $con-\>connect\_error); } include("auth\_login.php"); $target\_dir = "images/uploads/"; $target\_file = $target\_dir . basename($\_FILES["fileToUpload"]["name"]); $uploadOk = 1; $imageFileType = pathinfo($target\_file,PATHINFO\_EXTENSION); // Check if image file is a actual image or fake image if(isset($\_POST["change"])) { move\_uploaded\_file($\_FILES["fileToUpload"]["tmp\_name"], $target\_file); if($check !== false) { echo "\<a href = profile.php\> Profile pciture has been changed \</a\>" . $check["mime"] . "."; $uploadOk = 1; } else { echo "File is not an image."; $uploadOk = 0; } }

I don’t know where I got that code from. I think it was from an example 

Do you know of an alternative way I can do this ?

In my opinion, I understood how to fix this.

Thank you for the information and your example.

As soon as I manage, I will show my results.

regards bestazy

Cheer. :slight_smile:

I have this code and it’s not working . When I click on the button and it takes me to my gallery and I click on the picture I want to upload, I just go straight back into the profile.lua page and nothings happens . 

local MultipartFormData = require("class\_MultipartFormData") local multipart = MultipartFormData.new() local path=system.pathForFile( "image.jpg", system.TemporaryDirectory ) multipart:addFile("Image", path, "image/jpg", "image.jpg") local params = {} params.body = multipart:getBody() params.headers = multipart:getHeaders() -- Headers not valid until getBody() is called. network.request("http://hash.x10host.com/cgi-bin/hash/upload.php", "POST", listener, params) local image local mime = require "mime" local bkgd = display.newRect( 0, 0, display.contentWidth, display.contentHeight ) bkgd:setFillColor( 0, 0, 0 ) local myRoundedRect = display.newRoundedRect(10, 50, 80, 50, 12) myRoundedRect.strokeWidth = 3 myRoundedRect:setFillColor(140, 140, 140) myRoundedRect:setStrokeColor(180, 180, 180) local sessionComplete = function(event) image = event.target print( "Camera ", ( image and "returned an image" ) or "session was cancelled" ) print( "event name: " .. event.name ) print( "target: " .. tostring( image ) ) if image then -- center image on screen image.x = display.contentWidth/2 image.y = 59 local w = image.width local h = image.height image.xScale = 0.3 image.yScale = 0.3 print( "w,h = ".. w .."," .. h ) end end local listener = function( event ) if media.hasSource( media.Camera ) then media.show( media.Camera, sessionComplete ) else native.showAlert("Corona", "Camera not found.") end return true end myRoundedRect:addEventListener( "tap", listener ) local myRoundedRect1 = display.newRoundedRect(10, 400, 150, 50, 12) myRoundedRect1.strokeWidth = 3 myRoundedRect1:setFillColor(140, 140, 140) myRoundedRect1:setStrokeColor(180, 180, 180) local Name = "Imagename" function uploadBinary ( filename, url, onComplete ) -- local path = system.pathForFile( filename ) -- local fileHandle = io.open( path, "rb" ) -- if fileHandle then if image then local params = { body = "image\_file=" .. mime.b64(tostring( image )) .. "&image\_filename="..Name } -- io.close( fileHandle ) local function networkListener ( event ) if (onComplete) then onComplete(event); end return true; end network.request( url, "POST", networkListener, params) end end local function networkListener( event ) if ( event.isError ) then print( "Network error!") else -- print ( "RESPONSE: " .. event.response) print ("Working") end end local function Upload () uploadBinary ( image, "http://www.test1.bugs3.com/Corona.php", networkListener) end myRoundedRect1:addEventListener( "tap", Upload )

upload.php:

$username = $\_SESSION['username']; if(isset($\_FILES['image'])){ $errors= array(); $file\_name = $\_FILES['image']['name']; $file\_size = $\_FILES['image']['size']; $file\_tmp = $\_FILES['image']['tmp\_name']; $file\_type = $\_FILES['image']['type']; $file\_ext=strtolower(end(explode('.',$\_FILES['image']['name']))); $extensions= array("jpeg","jpg","png"); if(in\_array($file\_ext,$extensions)=== false){ $errors[]="extension not allowed, please choose a JPEG or PNG file."; } if($file\_size \> 2097152) { $errors[]='File size must be 2 MB'; } if(empty($errors)==true) { move\_uploaded\_file($file\_tmp,"uploads/".$file\_name); $store=mysqli\_query($conn,"UPDATE users SET userPic='$userPic' WHERE username='$username'"); mysqli\_query($conn,$store); echo "Success"; }else{ print\_r($errors); echo"it failed"; } }

I am connected to the internet but I just didn’t post that code above