I have a PHP Web Service that can insert a new row to my database if I hardcode the values in to the SQL query directly. But when I try to do this using variables passed to the PHP script from my Swift function it breaks down. I have add print statements to my Swift so I am confident that the values are being passed to the function correctly and the error must lie in the lines afterwards.
PHP: I have commented the SQL query line out with the hardcoded values – Carrots, but this query does work so I think PHP->SQL is working ok, but Swift->PHP is the problem.
<?php $servername = "localhost"; $username = "*******"; $password = "*****"; $dbname = "*******"; $product_name = $_POST['product_name'] ?? 'DefaultProduct'; $code = $_POST['code'] ?? 'DefaultCode'; $Brands = $_POST['brands'] ?? '1'; $Comp1Mat = $_POST['Comp1Mat'] ?? 'DefaultMat'; $Comp2Mat = $_POST['Comp2Mat'] ?? '1'; // Create connection $conn = new mysqli($servername, $username, $password, $dbname); // Check connection if ($conn->connect_error) { die("Connection failed: " . $conn->connect_error); } //$sql = "INSERT INTO Products (product_name, code) VALUES ('Carrots', '0135')"; $sql = $conn->prepare("INSERT INTO Products (product_name, code, brands, Comp1Mat, Comp2Mat) VALUES (?, ?, ?, ?, ?)"; $sql->bind_param("isssi", $product_name, $code, $Brands, $Comp1Mat, $Comp2Mat); $sql->execute(); $sql->close(); if ($conn->query($sql) === TRUE) { echo "New record created successfully"; } else { echo "Error: " . $sql . "<br>" . $conn->error; } $conn->close(); ?>
Swift:
func addProduct(product_name: String, code: String, brands: String, Comp1Mat: String, Comp2Mat: String){ print(product_name) print(code) print(brands) print(Comp1Mat) print(Comp2Mat) let insertProductURL = URL(string: "http://recyclingmadesimple.xyz/insertproduct.php")! var urlRequest = URLRequest(url: insertProductURL) urlRequest.httpMethod = "POST" // Set HTTP Request Headers urlRequest.setValue("application/json", forHTTPHeaderField: "Accept"); urlRequest.setValue("application/json", forHTTPHeaderField: "Content-Type"); let postString = "product_name=(product_name)&code=(code)&brands=(brands)&Comp1Mat=(Comp1Mat)&Comp2Mat=(Comp2Mat)" urlRequest.httpBody = postString.data(using: .utf8) let task = URLSession.shared.dataTask(with: urlRequest) { (data, response, error) in if error != nil { print("error = (String(describing: error))") return } print("response - (String(describing: response))") let responseString = NSString(data: data!, encoding: String.Encoding.utf8.rawValue) print("response string - (String(describing: responseString))") } task.resume() }
Error:
response - Optional(<NSHTTPURLResponse: 0x281191600> { URL: http://recyclingmadesimple.xyz/insertproduct.php } { Status Code: 500, Headers { Connection = ( "Upgrade, close" ); "Content-Length" = ( 0 ); "Content-Type" = ( "text/html; charset=UTF-8" ); Date = ( "Thu, 17 Jun 2021 12:38:25 GMT" ); Server = ( Apache ); Upgrade = ( "h2,h2c" ); Vary = ( "User-Agent" ); "X-Powered-By" = ( "PHP/7.4.16" ); } }) response string - Optional()
Many thanks.
Advertisement
Answer
I got this working after taking on board the suggestions. Thank you all. I changed the parsing to JSON in swift and improved the binding of variables in the PHP file.
PHP:
<?php $code = $_POST["code"]; // Create connection $con=mysqli_connect("localhost","X","X","X"); // Check connection // Return the error code if the connection is not successful. if (mysqli_connect_errno()) { echo "Failed to connect to MySQL: " . mysqli_connect_error(); } /* create a prepared statement */ // A prepared statement is one that is loaded initially and then executed many times over and over when we attach (bind) new variables to the placeholders we have inserted. We use ? marks to signify placeholders than must be later filled with values. $stmt = mysqli_prepare($con, "SELECT product_name, brands, Comp1Mat, Comp2Mat, Comp3Mat, Comp1Name, Comp2Name, Comp3Name FROM Products WHERE code=?"); // Bind the parameters the user has entered with the ? marks in the SQL query mysqli_stmt_bind_param($stmt, "s", $code); /* execute query */ mysqli_stmt_execute($stmt); // Bind the results we get with some new variable that we will output in the print statement. mysqli_stmt_bind_result($stmt, $product_name, $brands, $Comp1Mat, $Comp2Mat, $Comp3Mat, $Comp1Name, $Comp2Name, $Comp3Name); /* fetch value */ mysqli_stmt_fetch($stmt); //create an array $emparray = array("code" => $code, "product_name" => $product_name, "brands" => $brands, "Comp1Mat" => $Comp1Mat, "Comp2Mat" => $Comp2Mat, "Comp3Mat" => $Comp3Mat, "Comp1Name" => $Comp1Name, "Comp2Name" => $Comp2Name, "Comp3Name" => $Comp3Name); printf(json_encode($emparray)); // Close connections mysqli_close($con); ?><?php
Swift:
func findSingleProduct(code: String){ // Completes an SQL query on the Products database to find a product by it's barcode number. // prepare json data let insertProductURL = URL(string: "http://recyclingmadesimple.xyz/service.php")! var urlRequest = URLRequest(url: insertProductURL) urlRequest.httpMethod = "POST" let postString = "code=(code)" urlRequest.httpBody = postString.data(using: String.Encoding.utf8) let task = URLSession.shared.dataTask(with: urlRequest) { 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] { let code = responseJSON["code"]! let product_name = responseJSON["product_name"]! let brands = responseJSON["brands"]! let Comp1Mat = responseJSON["Comp1Mat"]! let Comp2Mat = responseJSON["Comp2Mat"]! let Comp3Mat = responseJSON["Comp3Mat"]! let Comp1Name = responseJSON["Comp1Name"]! let Comp2Name = responseJSON["Comp2Name"]! let Comp3Name = responseJSON["Comp3Name"]! print(code, brands, product_name, Comp1Mat, Comp2Mat, Comp3Mat, Comp1Name, Comp2Name, Comp3Name) } } task.resume() }