Url issue in swift 3.0 using Alamofire - swift

I am trying to send sms and my url with numbers is "http://api.appname.my/sendSms.php?message=hello&phone=687985<6123488<60149041982" but it get shorten to this "http://api.appname.my/sendSms.php?message=hello&phone=687985" so why it is removing other numbers.Here is my code
number = number + "60149041982"
let url = "http://api.appname.my/sendSms.php?message=hello&phone=\(number)"
Alamofire.request(url).response{ (responseObject) -> Void in
print(responseObject)
}

I think your should encode the < character to %3C
let urlString = "http://api.appname.my/sendSms.php?message=hello&phone=\(number)"
let url = urlString.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)
print("Result: " + url!)
// Result: http://api.appname.my/sendSms.php?message=hello&phone=687985%3C6123488%3C60149041982

Related

Swift unwanted URL percent encoding

I'm trying to format a URL for use in accessing an API. The documentation for the api specifies a URL that contains the "[" and "]" characters in it. When I create a URL from my string in Swift, it is adding percent encoding and changing these characters to "%5B" and "%5D".
How do I tell swift to not percent encode these characters? Thanks!
func attemptPubgIDLookup (playerName: String, completion: #escaping (String) -> Void) {
let region = "pc-na"
let urlString = "https://api.playbattlegrounds.com/shards/" + region + "/players?filter[playerNames]=" + playerName
let finalUrl = URL(string:urlString)
if let finalUrl = finalUrl {
var urlRequest = URLRequest(url: finalUrl)
urlRequest.httpMethod = HTTPMethod.get.rawValue
urlRequest.addValue(pubgApiKey, forHTTPHeaderField: "Authorization: Bearer")
urlRequest.addValue("application/vnd.api+json", forHTTPHeaderField: "Accept")
Alamofire.request(urlRequest)
.responseJSON(completionHandler: { (response) in
debugPrint(response)
})
}
}
That's what you want. When the server receives your request it will decode the URL...
%5B is '[' and %5D is ']'
This is called percent encoding and is used in encoding special characters in the url parameter values.

Image to String using Base64 in swift 4

my php code creates an empty image on server
here is my code (swift4) :
var encoded_img = imageTobase64(image: image1.image!)
func convertImageToBase64(image: UIImage) -> String {
let imageData = UIImagePNGRepresentation(image)!
return imageData.base64EncodedString(options: Data.Base64EncodingOptions.lineLength64Characters)
}
php code :
$decodimg = base64_decode(_POST["encoded_img"]);
file_put_contents("images/".$imgname,$decodimg);
And the code to prepare the request:
#IBAction func BtnSend(_ sender: UIButton) {
var url = "http://xxxxxx/msg.php"
var encoded_img = imageTobase64(image: image1.image!)
let postData = NSMutableData(data: ("message=" + message).data(using: String.Encoding.utf8)!)
postData.append(("&encoded_img=" + encoded_img).data(using: String.Encoding.utf8)!)
request = NSMutableURLRequest(url: NSURL(string: url)! as URL,
cachePolicy: .useProtocolCachePolicy,
timeoutInterval: 20.0)
request.httpMethod = "POST"
request.httpBody = postData as Data
let session = URLSession.shared
let dataTask = session.dataTask(with:
request as URLRequest, completionHandler:
{ (data, response, error)-> Void in
...
})
dataTask.resume()
The fundamental issue is that your x-www-form-urlencoded request is not well-formed. You have explicitly requested it to create base64 string with newline characters in it, but those are not allowed in x-www-form-urlencoded unless you percent encode them. Plus, we don't know what sort of characters are inside message.
I would suggest:
Not request newline characters to be added to the base64 string unless you really needed them; but
Percent escape the string values, anyway, as I don't know what sort of values you have for message.
Thus:
let parameters = [
"message": message,
"encoded_img": convertToBase64(image: image1.image!)
]
let session = URLSession.shared
let url = URL(string: "http://xxxxxx/msg.php")!
var request = URLRequest(url: url, timeoutInterval: 20.0)
request.httpMethod = "POST"
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type") // not necessary, but best practice
request.setValue("application/json", forHTTPHeaderField: "Accept") // again, not necessary, but best practice; set this to whatever format you're expecting the response to be
request.httpBody = parameters.map { key, value in
let keyString = key.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)!
let valueString = value.addingPercentEncoding(withAllowedCharacters: .urlQueryValueAllowed)!
return keyString + "=" + valueString
}.joined(separator: "&").data(using: .utf8)
let dataTask = session.dataTask(with:request) { data, response, error in
guard error == nil,
let data = data,
let httpResponse = response as? HTTPURLResponse,
(200 ..< 300) ~= httpResponse.statusCode else {
print(error ?? "Unknown error", response ?? "Unknown response")
return
}
// process `data` here
}
dataTask.resume()
where
func convertToBase64(image: UIImage) -> String {
return UIImagePNGRepresentation(image)!
.base64EncodedString()
}
and
extension CharacterSet {
/// Character set containing characters allowed in query value as outlined in RFC 3986.
///
/// RFC 3986 states that the following characters are "reserved" characters.
///
/// - General Delimiters: ":", "#", "[", "]", "#", "?", "/"
/// - Sub-Delimiters: "!", "$", "&", "'", "(", ")", "*", "+", ",", ";", "="
///
/// In RFC 3986 - Section 3.4, it states that the "?" and "/" characters should not be escaped to allow
/// query strings to include a URL. Therefore, all "reserved" characters with the exception of "?" and "/"
/// should be percent-escaped in the query string.
///
/// - parameter string: The string to be percent-escaped.
///
/// - returns: The percent-escaped string.
static var 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
}()
}
Alternatively, you could consider using Alamofire which gets you out of the weeds of creating well-formed x-www-form-urlencoded requests.

SWIFT URL String build

How do I build the URL as below:
/sap/opu/odata/SAP/ZTM_FOR_MOBILITY_SRV/BusinessPartnerSet('BP-CR-EM01')/?$format=json
I want specifically the part - BusinessPartnerSet('BP-CR-EM01').
BP-CR-EM01 value is dynamic value.
let newUrl = url + "'\(businessPartners[myIndex].partnerId)'"
url has the fixed URL and the + operator followed by dynamic value. Please help me with your suggestions.
I recommend to use URLComponents
var components = URLComponents(string: "http://mycompany.com")!
components.path = "/sap/opu/odata/SAP/ZTM_FOR_MOBILITY_SRV/BusinessPartnerSet('\(businessPartners[myIndex].partnerId)')/"
components.queryItems = [URLQueryItem(name: "$format", value:"json")]
if let url = components.url {
print(url)
// or if you need the string
print(url.absoluteString)
}

Reading URLS in JSON api with swift

For work we have a third party company which supply a JSON api for some functionality. The JSON contains urls which I try to map in my code with URL(string: ...) but this fails on some urls which have spaces.
For example:
var str = "https://google.com/article/test test.html"
let url = URL(string: str) //nil
Should I ask the third party to encode their URLs ?
Is this normal or should I try to add encoding myself?
Encoding myself is hard I think because the path should be encoded different from the query and the host shouldn't be encoded etc.
Or am I overthinking this?
If the URL contains spaces in its path, escape the characters with addingPercentEncoding(withAllowedCharacters passing the urlPathAllowed character set:
let str = "https://google.com/article/test test.html"
if let escapedString = str.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlPathAllowed),
let url = URL(string:escapedString) {
print(url)
} else {
print("url \(str) could not be encoded")
}
What I would do if I were you, is to split the string up on the space, try converting each of the elements to a url, and when that works save it in your variable.
var str = "https://google.com/article/test test.html"
var url: URL? = nil
for urlString in str.components(separatedBy: .whitespacesAndNewlines) {
let url = URL(string: urlString)
if url != nil {
break
}
}
// url might be nil here, so test for value before using it
If each URL that you get from the API is in the format in your example, you can instead just grab the first element after spitting the string.
var str = "https://google.com/article/test test.html"
if let urlString = str.components(separatedBy: .whitespacesAndNewlines).first {
let url = URL(string: urlString)
}
// url might be nil here, so test for value before using it

swift euc-kr korean encoding not working. But works in python

I am writing some code to parse korean text from server encoded with euc-kr korean encoder.
When I just do the same encoding in Python, it works as expected.
But when I do it as following, encoding doesn't work. The result is unreadable.
In Python :
string = u'안녕하세요.'.encode('eucKR')
In Swift :
let encoding:UInt = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(
CFStringEncodings.EUC_KR.rawValue))
let encodedData = "안녕하세요.".data(using: String.Encoding(rawValue: encoding))!
What the difference between those 2 encodings ?
Following are full source codes for both python and swift. I still stuck on the encoding part. Is the problem related to alamofire post request?
Python:
import requests
from pattern import web
string = u'저는 내일 바빠서 학교에 못갑니다.'.encode('eucKR')
r = requests.post("http://nlp.korea.ac.kr/~demo/dglee/komatag.php", data={'formradio1': '', 'formradio2': 'ems', 'textarea': string})
dom = web.Element(r.text)
main = dom('tr')
for item in main:
result = web.plaintext(item.source)
a = result.encode('ISO-8859-1')
t=a.decode('eucKR')
print(t)
Swift:
override func viewDidLoad() {
let string: NSString = NSString(string: "안녕하세요")
let encodedEucKr = stringToEuckrString(stringValue: string as String)
print(encodedEucKr)
Alamofire.request("http://nlp.korea.ac.kr/~demo/dglee/komatag.php", method: .post, parameters: ["formradio1":"", "formradio2":"ems", "textarea": encodedEucKr], headers: nil).responseString { response in
switch(response.result) {
case .success(_):
if let data = response.result.value{
print(response.result.value)
}
break
case .failure(_):
print(response.result.error)
break
}
}
}
func stringToEuckrString(stringValue: String) -> String {
let encoding:UInt = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(
CFStringEncodings.EUC_KR.rawValue))
let encodedData = stringValue.data(using: String.Encoding(rawValue: encoding))!
let attributedString = try? NSAttributedString(data: encodedData, options:[:], documentAttributes: nil)
if let _ = attributedString {
return attributedString!.string
} else {
return ""
}
}
It was not easy for two reasons...
Sending form data in EUC-KR is not considered to be standard-compliant in modern web technologies and standards.
The response sent from your server is sort of broken, in that Swift cannot decode the result as a valid EUC-KR text.
(This seems to be a bug of your server side code.)
Anyway, when you need to send a web form based request to your server in EUC-KR:
Create a EUC-KR byte sequence from the original
Percent-escape it. You may need to do it by yourself
Put entire request in an HTTP request body
Add proper MIME type header
Some details depend on the server. I have never used Alamofire, so I do not know if Alamofire supports such things.
Here I show you an example using a normal URLSession:
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
sendRequest(string: "안녕하세요")
}
func sendRequest(string: String) {
let rawEncoding = CFStringConvertEncodingToNSStringEncoding(CFStringEncoding(CFStringEncodings.EUC_KR.rawValue))
let encoding = String.Encoding(rawValue: rawEncoding)
let url = URL(string: "http://nlp.korea.ac.kr/~demo/dglee/komatag.php")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
//Create an EUC-KR byte sequece
let eucKRStringData = string.data(using: encoding) ?? Data()
//Percent-escape, you need to do it by yourself
//(Though, most servers accept non-escaped binary data with its own rules...)
let eucKRStringPercentEscaped = eucKRStringData.map {byte->String in
if byte >= UInt8(ascii: "A") && byte <= UInt8(ascii: "Z")
|| byte >= UInt8(ascii: "a") && byte <= UInt8(ascii: "z")
|| byte >= UInt8(ascii: "0") && byte <= UInt8(ascii: "9")
|| byte == UInt8(ascii: "_") || byte == UInt8(ascii: ".") || byte == UInt8(ascii: "-")
{
return String(Character(UnicodeScalar(UInt32(byte))!))
} else if byte == UInt8(ascii: " ") {
return "+"
} else {
return String(format: "%%%02X", byte)
}
}.joined()
//In application/x-www-form-urlencoded format, you send data in a URL-query like format.
let paramString = "formradio1=&formradio2=ems&textarea=\(eucKRStringPercentEscaped)"
//As all non-ASCII characters are percent-escaped, .isoLatin1 works well here.
let bodyData = paramString.data(using: .isoLatin1)!
//Form data needs to be sent as a body of HTTP protocol.
request.httpBody = bodyData
//MIME type for usual form data is "application/x-www-form-urlencoded".
request.addValue("application/x-www-form-urlencoded", forHTTPHeaderField: "Content-Type")
//URLRequest is ready and you can start dataTask here.
let task = URLSession.shared.dataTask(with: request) {data, response, error in
if let error = error {
print("Error:", error)
}
if let response = response {
print("Response:", response)
}
//The response may not be valid EUC-KR; you need to decode it while accepting invalid bytes.
if let data = data {
var result = ""
var i = 0
while i < data.count{
let ch = data[i]
if ch < 0x80 {
result += String(Character(UnicodeScalar(UInt32(ch))!))
} else if
i + 2 <= data.count,
let ch2 = String(data: data.subdata(in: i..<i+2), encoding: encoding)
{
result += ch2
i += 1
} else {
result += "?"
}
i += 1
}
print("Result:", result)
}
}
//Do not forget to resume the created task.
task.resume()
//And remember you should not do anything after you invoke an async task.
}
If your server side can handle UTF-8 requests and responses properly, the code above can be far more simple. Using EUC-KR in web services is sort of outdated. You'd better adopt UTF-8 soon.