I want to post some data to my php page, I've tested two ways to do so but non of them worked :
let parameters = [
"name": "test",
]
Alamofire.request(URL(string: "http://www.tameshkshop.ir/11.php")!, method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: [:]).responseJSON { (response) in
print(response.request) // original URL request
print(response.response) // URL response
print(response.data) // server data
print(response.result) // result of response serialization
let responseString = String(data: response.data!, encoding: .utf8)
print(responseString)
}
the second way :
var request = URLRequest(url: URL(string: "http://www.tameshkshop.ir/11.php")!)
request.httpMethod = "POST"
let postString = "name=\(FinallFactorViewController.name)"
request.httpBody = postString.data(using: .)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else { // check for fundamental networking error
print("error=\(error)")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 { // check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(response)")
}
let responseString = String(data: data, encoding: .utf8)
let index = responseString?.index((responseString?.startIndex)!, offsetBy: 4)
let done = responseString?.substring(to: index!)
in the php page, I get the posted value and echo them like this :
echo $_POST['name'];
but it I get nothing in return .
what is wrong ? where am I doing is wrong ?
Your POST service is waiting for for httpBody parameters, not JSON. I did check this on postman. Use the following code to make your request:
let parameters = ["name":"Name"]
Alamofire.request(.POST, "http://tameshkshop.ir/11.php", parameters: parameters)
.responseString(completionHandler: { response in
print(response.result.value)
})
The output:
"test : Name |"
EDIT:
You can't make a request using HTTP since iOS 9. Instead use HTTPS or Allow arbitrary loads in your .plist https://stackoverflow.com/a/33712228/5006492 Before going to production disable Allow arbitrary loads, is a security risk use HTTP. Get a SSL certificate for your site.
Related
I hope you all are doing well and staying safe! :)
I am new to iOS programming. I am trying to post values from a textfield to a MYSQL Database. As a first step, I tried to just print the values received on the PHP end.
The values are printed on the Swift end but on the PHP end, an empty string(null) is received. Could you please help and let me know why the string received on PHP end is null? Please help! I am stuck and unsure of what to do next.
I have tried retrieving values from the database and that code works perfectly fine.
Thanks in advance!
EDITED:
This has been now fixed. The correct code is below -
Swift Code:
struct DatatoPost : Codable{
var name : String
init() {
name = "Empty String"
}
}
var myDatatoPost = DatatoPost()
//Protocol created for this structure so that it can be applied to multiple class (View Controllers) that create a delegate for it(ManageDataDelegate)
protocol ManageDataDelegate {
func updateViewController(_ myManager : ManageData, saveOutputData: OutputData)
func didFailError(error : Error)
}
/* what action is expected to be taken on data reached through PHP file*/
struct ManageData {
var delegate : ManageDataDelegate?
var data : Data
init() {
data = Data()
}
//create POST URL based on function - this is the URL to post data to the backend.
mutating func postPHPData(){
let urlPostString = myConstant.baseURL + myConstant.postPHPValue
print(urlPostString)
performPostOperation(urlPostString)
}
//Steps to create URL and other related objects - prepare data for parsing.
mutating func performPostOperation(_ urlPostString : String) {
//1. Create URL
if let url = URL(string: urlPostString){
//Create request variable
var request : URLRequest = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
do{
let params : [String : Encodable] = ["name": myDatatoPost.name]
data = try JSONSerialization.data(withJSONObject: params, options: .init())
let body = Data(data).base64EncodedData()
print("Data is: ")
let dataString = String(data: data, encoding: .utf8)
print(dataString)
request.httpBody = body
let requestString = String(data: request.httpBody!, encoding: .utf8)
print("Request String is:")
print(requestString)
//2. Create URLSession
let session = URLSession(configuration: .default)
//3. Give the session a task
let task = session.dataTask(with: request as URLRequest, completionHandler: handlePOST(data:response:error:))
//4. Start the session
task.resume()
}catch{
print(error)
}
}
}
//Function that lists the activities that need to be completed in the URL session - GET Data.
func handlePOST(data : Data?, response : URLResponse?, error: Error?){
if error != nil {
delegate?.didFailError(error: error!)
print("error is")
print(error!)
return
}
if let safeData = data{
let dataString = String(data: safeData, encoding: .utf8)
print(dataString)
}
print(response)
}
}
PHP Code:
<?php
echo "we are here";
// Create connection
$con = mysqli_connect("localhost","username","password","dbname");
echo "we are here again";
// Check connection
if (mysqli_connect_errno())
{
echo "Failed to connect to MySQL: ";
}
$postdata = json_decode(file_get_contents("php://input"),TRUE);
$decoded = base64_decode($postdata);
echo "decoded!";
print_r($decoded,true);
//this value is not printed
echo "postdata";
echo $postdata->name;
//this value is not printed
$name= $postdata["name"];
echo "Name";
echo $postdata["name"];
//this value is not printed
echo "Base 64";
echo base64_decode($postdata["name"]);
echo base64_decode($postdata->name);
//This value is not printed
if (empty($postdata["name"])){
echo "String is empty";
//this is printed
}
if (empty($postdata->name)){
echo "String is empty";
//This is printed
}
echo "Its done";
// Close connections
mysqli_close($con);
?>
You have specified your request’s Content-Type to be application/json. So it should be JSON, free of base64 encoding. The only time you should use base64-encoding is if you are trying to send binary data in JSON. (And even then, in that case, we would reach for application/x-www-form-urlencoded request, not application/json request.)
Anyway, to send JSON request and parse JSON response:
protocol ManageDataDelegate: class {
func didFailError(error: Error)
func didReceiveResponse(object: Any)
}
/* what action is expected to be taken on data reached through PHP file*/
struct ManageData {
weak var delegate: ManageDataDelegate? // delegates should always be weak to avoid strong reference cycle; obviously `ManageDataDelegate` must be class protocol
//create POST URL based on function - this is the URL to post data to the backend.
func postPHPData(name: String) {
let urlPostString = URL(string: MyConstant.baseURL)!.appendingPathComponent(MyConstant.postPHPValue)
print(urlPostString)
performPostOperation(urlPostString, name: name)
}
//Steps to create URL and other related objects - prepare data for parsing.
func performPostOperation(_ url: URL, name: String) {
//Create request variable
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
do {
let params = ["name": name]
let body = try JSONSerialization.data(withJSONObject: params)
// 1. for diagnostic purposes, let's look at the JSON
if let json = String(data: body, encoding: .utf8) {
print("JSON is:", json)
}
request.httpBody = body
//2. Create URLSession
let session = URLSession(configuration: .default)
//3. Give the session a task
let task = session.dataTask(with: request, completionHandler: handlePOST(data:response:error:))
//4. Start the session
task.resume()
//5. If creating a URLSession locally, make sure to invalidate it when the request is done or else you will leak memory; better, create one `URLSession` and reuse it for all of your requests (and then you don't need/want to invalidate it)
session.finishTasksAndInvalidate()
} catch {
print(error)
}
}
enum ManageDataError: Error {
case unknownError(Data?, URLResponse?, Error?)
case notJsonResponse(String)
}
//Function that lists the activities that need to be completed in the URL session - GET Data.
func handlePOST(data: Data?, response: URLResponse?, error: Error?) {
guard let responseData = data, error == nil else {
let error = error ?? ManageDataError.unknownError(data, response, error)
delegate?.didFailError(error: error)
print("error is")
print(error)
return
}
if let object = try? JSONSerialization.jsonObject(with: responseData) {
delegate?.didReceiveResponse(object: object)
} else if let string = String(data: responseData, encoding: .utf8) {
delegate?.didFailError(error: ManageDataError.notJsonResponse(string))
} else {
delegate?.didFailError(error: ManageDataError.unknownError(data, response, error))
}
print(response ?? "No response")
}
}
There are a variety of refinements buried in the above (if creating a session, you must invalidate it when finished; passing responses to the delegate; making sure delegate reference is weak to avoid strong reference cycles; etc.), but hopefully this illustrates the idea: No base64-encoding is needed or desired with JSON requests.
Note, you have specified the request’s Accept to also be application/json so I would make sure it did precisely that:
<?php
header("Content-Type: application/json");
// Create connection
$con = mysqli_connect("localhost","username","password","dbname");
// Check connection
if (mysqli_connect_errno())
{
$result = [
"success" => false,
"message" => "Failed to connect to MySQL: " . mysqli_connect_error()
];
echo json_encode($result, JSON_PRETTY_PRINT);
exit();
}
$postdata = json_decode(file_get_contents("php://input"), true);
if (isset($postdata["name"]))
{
$result = [
"success" => true,
"name" => $postdata["name"]
];
}
else
{
$result = [
"success" => false,
"message" => "'name' not found",
"postdata" => $postdata
];
}
echo json_encode($result, JSON_PRETTY_PRINT);
// Close connections
mysqli_close($con);
?>
So, this parses the JSON and checks for name, but returning a JSON response, which is what the client was looking for.
There are other refinements I would suggest (e.g. I would use JSONEncoder and JSONDecoder rather than JSONSerialization; not create new URLSession for every request; usually a “network controller” like this would be a reference type so that you can use the same one wherever needed; I would use a framework such as Laravel in the server code, etc.), but I did not want to stray too far from the question at hand.
Hi all I am trying my hands on Swift and I am trying to post users registration data. I know how to do it firebase but my main project is in php mysql so I want to connect it with swift
#IBAction func signUp(_ sender: Any) {
//check textfield data
checkTextFields()
//create user
let url = NSURL(string: "http://localhost:8888/helo/register.php")
let request = NSMutableURLRequest(url: url! as URL)
request.httpMethod = "POST"
//apending body to url
let body = "Fullname=\(name.text!.lowercased())&userName=\(userName.text!.lowercased())&emailAddress=\(emailAddress.text!.lowercased())&password=\(password.text!.lowercased())"
request.httpBody = body.data(using: String.Encoding.utf8)
//lunching
URLSession.shared.dataTaskWithRequest(request as URLRequest, completionHandler: { (data:NSData?, response:URLResponse?, error:NSError?) in
if error == nil{
dispatch_async(dispatch_get_main_queue(),{
do {
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as?
NSDictionary
guard let parseJSON = json else{
print("Error while parsing")
return
}
let id = parseJSON["id"]
if id != nil {
print(parseJSON)
}
}catch{
print("Caugth an error: \(error)")
}
})
}else{
print("error: \(error)")
}
} )
}
I am getting an error on the line where I have commented as as lunching which say
Cannot convert value of type '(NSData?, URLResponse?, NSError?) -> ()' to expected argument type '(Data?, URLResponse?, Error?) -> Void'
I am new to Swift any help is welcome thank you all. I am using Xcode 9
After enough reading, I just realised I was doing a very tedious and using orthodox method when things have improved. I removed the whole code and did everything with Alamofire. Its really easy and straight forward. I will post the code below to help others who encounter similar problems later on.
//Constant that holds the URL for our web servicer
let URL_USER_REGISTER = "http://localhost:8888/members/register.php?"
Alamofire.request(URL_USER_REGISTER, method: .post, parameters: parameters).responseJSON{
response in
//printing response
print(response)
//getting json value from the server
if let result = response.result.value {
//converting it as NSDictionary
let jsonData = result as! NSDictionary
//displaying the message in label
self.lableMessage.text = jsonData.value(forKey: "message") as! String?
}
}
you have to first import Alamofire.
The code I've posted here is a shortened versions with just the essentials to the issue. When put through rigorous error testing, it appears that there are no issues either within the request, within the server, or within the return code, except for the fact that the response from the server says "Function": null instead of "Function": "addUser" as it should. Is there something I'm doing wrong on either end? It just seems to not be recognizing the posted variables, but I've used this code numerous times in other apps and servers and it seems to be failing here for some reason I cannot see. Thank you for any assistance.
Here is my PHP on the server:
<?php
$t = $_POST["function"];
$do = array("Success"=>true, "Function"=> $t);
echo json_encode($do);
?>
Here is the swift I'm using to make the request:
let params = ["function": "addUser"] as [String: AnyObject]?
fetchData("https://pdt.pitchprogress.net/SamplePHP.php", token: nil, parameters: params, method: "POST", onCompletion: { (success, data) -> Void in
if success {
do {
let json = try JSON(data: data!)
if json["Success"].boolValue == true {
print("success!")
print(json.description)
print(json["Function"].stringValue)
}
}
}
})
func fetchData(_ feed:String,token:String? = nil,parameters:[String:AnyObject]? = nil,method:String? = nil, onCompletion:#escaping (_ success:Bool,_ data:Data?)->Void){
DispatchQueue.main.async {
if let unwrapped_url = URL(string: feed){
let request = NSMutableURLRequest(url: unwrapped_url)
if let parm = parameters {
if let data = (try? JSONSerialization.data(withJSONObject: parm, options:[])) as Data? {
request.httpBody = data
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("\(data.count)", forHTTPHeaderField: "Content-Length")
}
}
if let unwrapped_method = method {
request.httpMethod = unwrapped_method
}
let sessionConfiguration = URLSessionConfiguration.default
sessionConfiguration.timeoutIntervalForRequest = 15.0
let session = URLSession(configuration: sessionConfiguration)
let taskGetCategories = session.dataTask(with: request as URLRequest, completionHandler: { (responseData, response, error) -> Void in
let statusCode = (response as! HTTPURLResponse?)?.statusCode
//println("Status Code: \(statusCode), error: \(error)")
if error != nil || (statusCode != 200 && statusCode != 201 && statusCode != 202){
onCompletion(false, nil)
} else {
onCompletion(true, responseData)
}
})
taskGetCategories.resume()
}
}
}
This is because you are sending the params as JSON while your API requires params as form data.
This code sends the params as simple form post and this retrieved successful response.
var request = URLRequest(url: URL(string: "http://app123.freeiz.com/Apis/samples/api4.php")!)
request.httpMethod = "POST"
var postString = ""
postString.append("function=value") // replace 'function' with your paramname and 'value' with your value'
request.httpBody = postString.data(using: .utf8)
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
// check for fundamental networking error
print("error=\(String(describing: error))")
return
}
if let httpStatus = response as? HTTPURLResponse, httpStatus.statusCode != 200 {
// check for http errors
print("statusCode should be 200, but is \(httpStatus.statusCode)")
print("response = \(String(describing: response))")
}
let responseString = String(data: data, encoding: .utf8)
if let unWrappedResponseString = responseString{
print(unWrappedResponseString)
}
}
task.resume()
I had once made a small wrapper for sending simple form data, If i find it I will update the answer with that. Till then you can try with this. Let me know how it goes..
Looks like your key is different use "function" instead of using "Function"
I'm developing an app in Swift 3 where I need to pass an integer value from the app to an online SQL server.
My Swift code is as following:
func saveData(data: Int) {
// prepare json data
let json: [String: Any] = ["matchScore": ["\(data)"]]
let jsonData = try? JSONSerialization.data(withJSONObject: json)
// create post request
let url = URL(string: "http://mywebpage.com/swift/addToSQL.php")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
// insert json data to the request
request.httpBody = jsonData
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard let data = data, error == nil else {
print(error?.localizedDescription ?? "No data")
return
}
let responseJSON = try? JSONSerialization.jsonObject(with: data, options: [])
if let responseJSON = responseJSON as? [String: Any] {
print(responseJSON)
}
}
task.resume()
}
And the part of the PHP file where I'm supposed to get the JSON data:
$jsonData = file_get_contents("php://input");
$json = json_decode($jsonData, true);
$matchScore = $json['matchScore'][1];
However, the database is not getting anything. I found out that if I set $matchScore = 42 (example) it works and posts to SQL database, so it has to be the parsing that's the issue.
What am I missing out here?
Thanks.
I'm relatively new to iOS development. Currently, I'm following the tutorial on making POST request to server in Swift. However, I'm getting error messages that I don't really understand what is wrong with it.
2016-01-08 14:44:48.991 test[24331:4311765] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9802)
error=Optional(Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, _kCFStreamErrorDomainKey=3, NSUnderlyingError=0x7c28c9b0 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, _kCFNetworkCFStreamSSLErrorOriginalValue=-9802, _kCFStreamErrorCodeKey=-9802, _kCFStreamErrorDomainKey=3, kCFStreamPropertySSLPeerTrust=<SecTrustRef: 0x7ae43c60>, kCFStreamPropertySSLPeerCertificates=<CFArray 0x7c28aad0 [0x4ef098]>{type = immutable, count = 1, values = (
0 : <cert(0x7c191330) s: localhost i: localhost>
)}}}, _kCFStreamErrorCodeKey=-9802, NSErrorFailingURLStringKey=https://localhost/, NSErrorPeerCertificateChainKey=<CFArray 0x7c28aad0 [0x4ef098]>{type = immutable, count = 1, values = (
0 : <cert(0x7c191330) s: localhost i: localhost>
)}, NSErrorClientCertificateStateKey=0, NSURLErrorFailingURLPeerTrustErrorKey=<SecTrustRef: 0x7ae43c60>, NSErrorFailingURLKey=https://localhost/})
POST request in Swift:
let myUrl = NSURL(string: "https://localhost");
let request = NSMutableURLRequest(URL:myUrl!);
request.HTTPMethod = "POST";
// Compose a query string
let postString = "firstName=James&lastName=Bond";
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding);
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
if error != nil
{
print("error=\(error)")
return
}
// You can print out response object
print("response = \(response)")
// Print out response body
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
//Let’s convert response sent from a server side script to a NSDictionary object:
do {
let myJSON = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary
// YOUR CODE HERE
if let parseJSON = myJSON {
// Now we can access value of First Name by its key
let firstNameValue = parseJSON["firstName"] as? String
print("firstNameValue: \(firstNameValue)")
}
} catch {
print(error)
}
}
task.resume()
Code in index.php:
<?php
// Read request parameters
$firstName= $_REQUEST["firstName"];
$lastName = $_REQUEST["lastName"];// Store values in an array
$returnValue = array(“firstName”=>$firstName, “lastName”=>$lastName);
// Send back request in JSON format
echo json_encode($returnValue);
?>
Your localhost is not https, it's http. In iOS 9 you'll have to disable that in your info.plist so it allows you to make requests to non-https targets.
Add this to your info.plist