I have to send NSAttributedString to mysql and be able to edit in on my website. I thought that the best idea will be converting NSAttributedString into array of Strings. But I have a problem with sending it. Firstly code(done thanks to one user of stack overflow:)):
func uploadNote(user: String, title: String, category: String, content: [String]) {
let URL: NSURL = NSURL(string: "http://site/uploadNote.php")!
let string = arrayToJSONBase64(content)
print(string)
let request:NSMutableURLRequest = NSMutableURLRequest(URL:URL)
request.HTTPMethod = "POST"
let bodyData = "content=\(string)"
request.HTTPBody = bodyData.dataUsingEncoding(NSUTF8StringEncoding);
print("appended data to body")
let task = NSURLSession.sharedSession().dataTaskWithRequest(request){ data, response, error in
print("Sent request")
}
task.resume()
}
func arrayToJSONBase64(arr: [String]) -> String {
let data = try?NSJSONSerialization.dataWithJSONObject(arr, options: .PrettyPrinted)
let contentJsonBase64 = data!.base64EncodedStringWithOptions(.Encoding64CharacterLineLength)
return contentJsonBase64
}
And php:
<?php
// uploadr.php
require_once 'log.php';
class Handler {
use Logger;
public function handleRequest($arg) {
try {
$this->log(__METHOD__);
$this->log(print_r($arg, true));
$json = base64_decode($arg['content']);
$this->log($json);
// just write to a file
file_put_contents('data.json', $json);
}
catch(PDOException $e) {
$this->log('Failed: ' . $e->getMessage());
}
catch( Exception $e) {
}
}
}
$handler = new Handler();
$handler->handleRequest($_POST);
log.php:
<?php
trait Logger {
function log($msg) {
file_put_contents('app.log', strftime('%Y-%m-%d %T ') . $msg . "\n", FILE_APPEND);
}
}
The problem is that when I send an array like ["one", "two", "three"] everything is ok, it's saved in data.json and everything is all right. But when I try to send HTML code my data.json looks like this:
MY OUTPUT
Related
I am creating an simple ios app that asks the user for userid and sends that to a database. This is my first app so i am new to app-database connection. Here is the entire code for the page that asks for the userid and sends that to the a php file.
//
// NextSecondViewController.swift
// DepressionApp1
//
// Created by Ashok Nambisan on 12/2/22.
//
import UIKit
import Foundation
struct ResponseObject<T: Decodable>: Decodable {
let form: T
}
struct Foo: Decodable {
let name: String
}
extension Dictionary {
func percentEncoded() -> Data? {
map { key, value in
let escapedKey = "\(key)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
let escapedValue = "\(value)".addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed) ?? ""
return escapedKey + "=" + escapedValue
}
.joined(separator: "&")
.data(using: .utf8)
}
}
extension CharacterSet {
static let urlQueryValueAllowed: CharacterSet = {
let generalDelimitersToEncode = ":#[]#" // does not include "?" or "/" due to RFC 3986 - Section 3.4
let subDelimitersToEncode = "!$&'()*+,;="
var allowed: CharacterSet = .urlQueryAllowed
allowed.remove(charactersIn: "\(generalDelimitersToEncode)\(subDelimitersToEncode)")
return allowed
}()
}
class NextViewController: UIViewController {
let URL = ""
#IBOutlet var Text: UITextView!
override func viewDidLoad() {
super.viewDidLoad()
initializeHideKeyboard()
}
func initializeHideKeyboard(){
//Declare a Tap Gesture Recognizer which will trigger our dismissMyKeyboard() function
let tap: UITapGestureRecognizer = UITapGestureRecognizer(
target: self,
action: #selector(dismissMyKeyboard))
//Add this tap gesture recognizer to the parent view
view.addGestureRecognizer(tap)
}
#objc func dismissMyKeyboard(){
//endEditing causes the view (or one of its embedded text fields) to resign the first responder status.
//In short- Dismiss the active keyboard.
view.endEditing(true)
}
#IBOutlet weak var labelf: UILabel!
#IBOutlet weak var textg: UITextField!
#IBAction func Submit(_ sender: Any) {
//created NSURL
let url = Foundation.URL(string: "http://ashok.local:8888/insert.php")!
//creating NSMutableURLRequest
var request = URLRequest(url: url)
request.httpMethod = "POST"
//setting the method to post
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField: "Accept")
//getting values from text fields
print(textg.text)
let parameters: [String: Any] = [
"userid": textg.text
]
request.httpBody = parameters.percentEncoded()
print("URLRequest: \(request)")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard
let data = data,
let response = response as? HTTPURLResponse,
error == nil
else { // check for fundamental networking error
print("error", error ?? URLError(.badServerResponse))
return
}
guard (200 ... 299) ~= response.statusCode else { // check for http errors
print("statusCode should be 2xx, but is \(response.statusCode)")
print("response = \(response)")
return}
do {
let responseObject = try JSONDecoder().decode(ResponseObject<Foo>.self, from: data)
print(responseObject)
} catch {
print(error) // parsing error
if let responseString = String(data: data, encoding: .utf8) {
print("responseString = \(responseString)")
} else {
print("unable to parse response as string")
}
}
}
task.resume()
//executing the task
}
#IBAction func previbutton(_ sender: Any) {
let vmc = storyboard?.instantiateViewController(withIdentifier: "second") as! SecondViewController
vmc.modalPresentationStyle = .fullScreen
present(vmc,animated:true)
}
}
Then here is the code for the config.php
<?php
define('DB_USERNAME', 'root');
define('DB_PASSWORD', 'root');
define('DB_SERVER', 'localhost');
define('DB_NAME', 'emotion');
try{
$pdo = new PDO("mysql:host=" . DB_SERVER . ";dbname=" . DB_NAME, DB_USERNAME, DB_PASSWORD);
// Set the PDO error mode to exception
$pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
} catch(PDOException $e){
die("ERROR: Could not connect. " . $e->getMessage());
}
?>
and insert.php:
<?php
// set up the response array
$response = array();
// check if the request method is POST
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
// get the userid from the POST request
$userid = $_POST['userid'];
// connect to the database
require_once "config.php";
// insert the record into the database
$sql = "INSERT INTO data (userid) VALUES (:userid)";
$stmt = $pdo->prepare($sql);
$stmt->bindParam(':userid', $userid);
$stmt->execute();
// set the success message in the response array
$response['error'] = false;
$response['message'] = 'Record inserted successfully';
} else {
// set the error message in the response array
$response['error'] = true;
$response['message'] = 'You are not authorized';
}
// return the response as JSON
echo json_encode($response);
// close the database connection
unset($pdo);
When i run the code on xcode, it gives me the status 500 error
I know my php-database connection is fine since when i just sent a number to the database in the userid column, it worked. However, when I connected the swift to the php for userid, it gives me a status 500 error and doesn't work. I don't know where the error is, could someone help me?
I am trying to create simple login and signup in swift with php mysql in backend. I was following "https://github.com/EMacco/ios-tutorials/tree/yummie-network-connection/Yummie" this project
I get the following error
The response is: {"data":[{"response":"Success","username":"Mohammad Tariq Shamim"}]} Error Response could not be decoded
I am getting response from the server but JSON is not getting decoded. Following is my code
enum Route {
static let baseurl = "http://arabscholar.net/android/"
case login
var description: String {
switch self {
case .login: return "login.php"
}
}
}
struct User: Decodable{ let username: String? let response: String? }
struct ApiResponse<T: Decodable>: Decodable {
let status: Int
let data: T?
let error: String?
}
AppError Swift file
enum AppError: LocalizedError {
case errorDecoding
case unknownError
case invalidUrl
case serverError(String)
var errorDescription: String? {
switch self {
case .errorDecoding:
return "Response could not be decoded"
case .unknownError:
return "Unknown error"
case .invalidUrl:
return "Url invalid"
case .serverError(let error):
return error
}
}
}
Main networking struct file
struct NetworkService {
static let shared = NetworkService()
private init() {}
func signin(username: String, password: String, completion: #escaping(Result<User, Error>) -> Void) {
let params = ["login": "user", "email": username, "password": password]
request(route: .login, method: .post, parameters: params, completion: completion)
}
private func request<T: Decodable>(route: Route, method: Method, parameters: [String: Any]? = nil, completion: #escaping(Result<T, Error>) -> Void) {
guard let request = createRequest(route: route, method: method, parameters: parameters) else {
completion(.failure(AppError.unknownError))
return
}
URLSession.shared.dataTask(with: request) { data, response, error in
var result: Result<Data, Error>?
if let data = data {
result = .success(data)
let responseString = String(data: data, encoding: .utf8) ?? "Could not stringify our data"
print("The response is: (responseString)")
} else if let error = error {
result = .failure(error)
print("The error is " + error.localizedDescription)
}
DispatchQueue.main.async {
self.handleResponse(result: result, completion: completion)
}
}.resume()
}
private func handleResponse<T: Decodable>(result: Result<Data, Error>?, completion: (Result<T, Error>) -> Void) {
guard let result = result else {
completion(.failure(AppError.unknownError))
return
}
switch result {
case .success(let data):
let decoder = JSONDecoder()
guard let response = try? decoder.decode(ApiResponse.self, from: data) else {
completion(.failure(AppError.errorDecoding))
return
}
if let error = response.error {
completion(.failure(AppError.serverError(error)))
return
}
if let decodedData = response.data {
completion(.success(decodedData))
} else {
completion(.failure(AppError.unknownError))
}
case .failure(let error):
completion(.failure(error))
}
}
private func createRequest(route: Route, method: Method, parameters: [String: Any]? = nil) -> URLRequest? {
let urlString = Route.baseurl + route.description
guard let url = urlString.asUrl else {return nil}
var urlRequest = URLRequest(url: url)
urlRequest.addValue("application/json", forHTTPHeaderField: "Content-Type")
urlRequest.httpMethod = method.rawValue
if let params = parameters {
switch method {
case .get:
var urlComponent = URLComponents(string: urlString)
urlComponent?.queryItems = params.map { URLQueryItem(name: $0, value: "($1)")}
urlRequest.url = urlComponent?.url
case .post:
let bodyData = try?JSONSerialization.data(withJSONObject: params, options: [])
urlRequest.httpBody = bodyData
}
}
return urlRequest
}
}
My PHP code
$postdata = json_decode( file_get_contents( "php://input" ), TRUE );
//$id = $postdata[ "email" ];
//$name = $postdata[ "password" ];
$result[ 'response' ] = "Success";
$result[ 'username' ] = "Mohammad Tariq Shamim";
// Store values in an array
$returnValue = array( $result );
$array['data'] = $returnValue;
// Send back request in JSON format
echo json_encode( $array );
//echo json_encode( array( 'response' => 'No data found for ' . $_POST[ 'email' ] ) );
I'm trying to write to a database and not able to get POST data from Swift into PHP. I've checked everything along the way and the data is present in request.httpBody before sending the request, but I get this error
"SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'order_id' cannot be null"
Also PHP prints an empty array of $request
Any help is appreciated. Racking my brain on this one!
Here's the code
SWIFT:
func saveNewProduct(product: ProductClass) {
//declare parameter as a dictionary which contains string as key and value combination.
let productDict: [String:Any] = ["order_id": product.order_id!,
"product_sku": product.product_sku!,
"product_description": product.product_description!,
"product_base_price": product.product_base_price!,
"product_price": product.product_price!,
"product_min_qty": product.product_min_qty!,
"product_qty": product.product_qty!,
"product_subtotal": product.product_subtotal!,
"product_imageURL": product.product_imageURL!]
let urlString: String = "https://www.mywebsite.com/dbinsertproduct.php"
guard let url = URL(string: urlString) else {
print("Error: cannot create URL")
return
}
//create the session object
let session = URLSession.shared
//create the URLRequest object using the url object
var request = URLRequest(url: url)
//set http method as POST
request.httpMethod = "POST"
do {
request.httpBody = try? JSONSerialization.data(withJSONObject: productDict, options: .prettyPrinted)
} catch let error {
print(error.localizedDescription)
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
let task = session.dataTask(with: request, completionHandler: {
data,response,error in
guard error == nil else {
return
}
guard let data = data else {
return
}
do {
//create json object from data
if let json = try JSONSerialization.jsonObject(with: data, options: .mutableContainers) as? [String: Any] {
print(json)
// handle json...
}
} catch let error {
print(error.localizedDescription)
}
})
task.resume()
}
PHP:
<?php include("dbclass.php"); ?>
<?php
$postdata = file_get_contents("php://input");
$request = json_decode($postdata, true);
$newProduct = new DBConnector('mysql.mysite.com', 'username', 'password', 'mysiteorders');
$p = $newProduct->dbInsertProduct($request);
error_log($p);
echo ($p);
?>
More PHP:
public function dbInsertProduct($request)
{
try {
$stmt = $this->prepare("INSERT INTO `products` (`order_id`,`product_sku`,`product_description`,`product_base_price`,`product_price`,`product_notes`,`product_min_qty`,`product_qty`,`product_subtotal`,`product_imageURL`) VALUES (:order_id,:product_sku,:product_description,:product_base_price,:product_price,:product_notes,:product_min_qty,:product_qty,:product_subtotal,:product_imageURL);");
$stmt->bindParam(':order_id', $request['order_id']);
$stmt->bindParam(':product_sku', $request['product_sku']);
$stmt->bindParam(':product_description', $request['product_description']);
$stmt->bindParam(':product_base_price', $request['product_base_price']);
$stmt->bindParam(':product_price', $request['product_price']);
$stmt->bindParam(':product_notes', $request['product_notes']);
$stmt->bindParam(':product_min_qty', $request['product_min_qty']);
$stmt->bindParam(':product_qty', $request['product_qty']);
$stmt->bindParam(':product_subtotal', $request['product_subtotal']);
$stmt->bindParam(':product_imageURL', $request['product_imageURL']);
error_log( print_r($request, TRUE) );
$stmt->execute();
} catch(PDOException $e) {
error_log($e->getMessage());
echo json_encode($e->getMessage());
}
}
UPDATE:
The request shows up as GET, not POST (verified with Charles proxy).
As you can see in the code, I'm setting request.httpMethod = "POST". Am I missing something else??
I found that the POST was being changed to GET upon redirect from www.mysite.com to mysite.com. Removing the 'www' did the trick.
I have an iOS application (Swift) which encodes some data and does a JSONSerialization and creates a JSON object. My code is below, I've done my best to keep it tidy, so I hope it makes sense:
struct Order: Codable {
let idQty: [FoodIdAndQuantity]
let collection: String
let name: String
let phone: Int
let doorNum: Int
let street: String
let postcode: String
}
struct FoodIdAndQuantity: Codable {
let itemId: Int
let qty: Int
}
class CheckoutServer: NSObject, URLSessionDataDelegate {
var inputValuesForItemAndQuantity = [Int:Int]()
var idQty = [FoodIdAndQuantity]()
var collection = String()
var name = String()
var phone = Int()
var doorNum = Int()
var street = String()
var postcode = String()
var request = URLRequest(url: NSURL(string: "http://192.168.1.100/api/AddOrder.php")! as URL)
func sendToDatabase() {
for(key,value) in inputValuesForItemAndQuantity {
idQty.append(FoodIdAndQuantity(itemId: key, qty: value))
}
let order = Order(idQty: idQty,collection: collection,name: name,phone: phone,doorNum: doorNum,street: street,postcode: postcode)
let encodedOrder = try? JSONEncoder().encode(order)
var json: Any?
request.httpMethod = "POST"
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
if let data = encodedOrder {
json = try? JSONSerialization.jsonObject(with: data, options: .allowFragments)
if var json = json {
if JSONSerialization.isValidJSONObject(json) {
do {
json = try JSONSerialization.data(withJSONObject: json, options: .prettyPrinted)
} catch {
print("There was a problem creating the JSON object")
}
} else {
print("not valid JSON")
}
}
}
let postParameters = "json="+String(describing: json!)
print(String(describing: json!)) //Print JSON for debugging purposes
request.httpBody = postParameters.data(using: .utf8)
let defaultSession = URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: request) { (data, response, error) in
if error != nil {
print("Failed to download data at Menu Type Items")
} else {
print("Data uploaded")
}
}
task.resume()
}
}
So the above code does the following:
Creates an encodable object called 'order'.
Creates a POST request to my API.
Passes the encoded JSON object via a POST parameter.
I've printed the json object that gets posted back to the console in XCode and that looks as follows:
{
collection = Delivery;
doorNum = 99;
idQty = (
{
itemId = 17;
qty = 5;
},
{
itemId = 1;
qty = 3;
}
);
name = James;
phone = 012345667;
postcode = LXU49RT;
street = Hope Street;
}
Next, I'll move over to my server/API which accepts the POST parameter.
Below is my AddOrder.php page:
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
require_once dirname(__FILE__) . '/DbOperation.php';
$json = $_POST["json"];
$db = new DbOperation();
$json = $db->addOrder($json);
}
And below is my DbOperation addOrder function:
public function addOrder($json) {
require dirname(__FILE__) . '/../../dbconnect.php';
$decoded = json_decode($json);
$collection = $decoded{"collection"};
$stmt2 = $pdo->prepare("INSERT INTO TestTable (collection) VALUES (:collection)");
$stmt2->bindParam(':collection',$collection);
$stmt2->execute();
}
It's worth noting that, whilst I try to fix this issue, I have created a test table in my Database which simply stores the collection element of the JSON.
The problem I have is, when I run my application and send the data, nothing gets stored in the database, and my apache error.log file says the Column 'collection' cannot be null. So I assume I am handling the POST parameter incorrectly at some point of my PHP. Unless the fault lies at a Swift level, which I'll add the Swift tag to this post if asked by an admin.
The full error is below:
[Wed Feb 28 15:44:55.178184 2018] [:error] [pid 520] [client 192.168.1.46:52400] PHP Fatal error: Uncaught PDOException: SQLSTATE[23000]: Integrity constraint violation: 1048 Column 'collection' cannot be null in /var/www/api/DbOperation.php:111\nStack trace:\n#0 /var/www/api/DbOperation.php(111): PDOStatement->execute()\n#1 /var/www/api/AddOrder.php(16): DbOperation->addOrder(NULL)\n#2 {main}\n thrown in /var/www/api/DbOperation.php on line 111
What I've tried
I've tried altering my AddOrder.php page to the following:
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
require_once dirname(__FILE__) . '/DbOperation.php';
//$json = $_POST["json"];
$json = json_decode(file_get_contents('php://input'),true);
$db = new DbOperation();
$json = $db->addOrder($json);
}
Your swift code doesn't make much sense. You have code that uses a JSONEncoder to encode your swift object into Data. If that succeeds, you then convert the data back to a Swift object using JSONSerialization. if that succeeds, you then use JSONSerialization.data(withJSONObject:options:) to convert your Swift object back to JSON data, and then use String(describing:) your insanely over-processed JSON Data to a string, which is very, very wrong.
Get rid of all that code. Try this instead:
func sendToDatabase() {
for(key,value) in inputValuesForItemAndQuantity {
idQty.append(FoodIdAndQuantity(itemId: key, qty: value))
}
let order = Order(idQty: idQty,collection: collection,name: name,phone: phone,doorNum: doorNum,street: street,postcode: postcode)
guard let encodedOrder = try? JSONEncoder().encode(order) else { return }
request.httpBody = encodedOrder
let defaultSession = URLSession(configuration: URLSessionConfiguration.default)
let task = defaultSession.dataTask(with: request) { (data, response, error) in
if error != nil {
print("Failed to download data at Menu Type Items")
} else {
print("Data uploaded")
}
}
task.resume()
}
The following is not valid code, and should throw a fatal "Cannot use object of type stdClass as array":
$decoded = json_decode($json);
$collection = $decoded{"collection"};
You probably want this:
$decoded = json_decode($json, true);
$collection = $decoded["collection"];
Or this:
$decoded = json_decode($json);
$collection = $decoded->collection;
I noticed a json decoding issue with incoming json from Swift 5 to php. Using file_put_contents in my php API, I found the json string from Swift looks like this
[{"Description":"box 3 of 3","Name":"Box S-7","Barcode":"1007","ComponentID":"50","Notes":"ok"}]
which if you convert with json_decode will throw an error, unless you remove the [ and ] from beginning and end of the string, respectively
$new_json = substr($json, 1, -1);
$decode = json_decode($new_json);
Hi guys i am using alamofire on a swift 3 iphone program, my problem is that i need to return a value from the php page my problem is that the value that comes back to me is this. How do I make sure that the value I return is: no prova#email.it
I hope I have explained
RETURN VALUE(NOT CORRECT):
SUCCESS: {
message = "no Optional(\"prova#email.it\")";
}
no Optional("prova#email.it")
SWIFT CODE:
import Foundation
import Alamofire
class User{
//URL to our web service
var email=""
var password=""
func PrintValue(){
// print(username);
//print(password);
}
func Login() -> String{
//var ris="";
var readvalue=""
let URLString = "http://localhost/test/login_mobile.php"
let parameters_value: Parameters = [
"email": email,
"password": password
]
//Sending http post request
Alamofire.request(URLString, method: .post, parameters: parameters_value).responseJSON
{
response in
//printing response
print(response)
//getting the 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
readvalue = (jsonData.value(forKey: "message") as! String?)!
print(readvalue)
}
}
return readvalue
}
}
PHP CODE:
<?php
include 'user.php';
header('Content-Type: application/json');
$email= $_POST['email'];
$password = $_POST['password'];
$ris['message']="";
$user = new User();
//procedo con il login
if($user->login($email,$password,"MOBILE")==true){
$ris['message']="yes";
}
else{
$ris['message']="no $email";
}
echo json_encode($ris);
?>
I think it can be done something like:
if let readvalue = jsonData.value(forKey: "message") as? String {
print(readvalue)
}
must print wihtout Optional
Just did this in a playground and it works as expected..
import UIKit
let response: [AnyHashable: Any] = [
"message": "hello world"
]
class MyCoolClass {
func login() {
var readvalue = ""
let jsonData = response as NSDictionary
readvalue = jsonData.value(forKey: "message") as! String
debugPrint("the readvalue is: \(readvalue)")
}
}
let instance = MyCoolClass()
instance.login()
This will print: "the readvalue is: hello world"
The code is not very failsafe...
You need to use nil coalescing to make your value non-optional. e.g. print(readvalue ?? "nil"). Something better would be reengineer your response handling to properly return a typed value or a specific error.