Start PHP with Swift - php

I wanted to send an email via a websever and php. Therefore I created a connection to my webserver (000webhoster).
Nearly everything works fine.
My main problem is, that I don't receive anything. I am not even sure, if the PHP code is even executed.
This is my current swift code:
func postToServer (){
print("button pressed")
var url: NSURL = NSURL(string: "http://www.bl1nd3d.herobo.com/email.php")!
var request: NSMutableURLRequest = NSMutableURLRequest(URL:url)
var bodyData = "data=something"
request.HTTPMethod = "POST"
request.HTTPBody = bodyData.dataUsingEncoding(NSUTF8StringEncoding)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler:{ response, data, error in
if let HTTPResponse = response as? NSHTTPURLResponse {
let statusCode = HTTPResponse.statusCode
if statusCode == 200 {
print("nice")
// TODO : Sent successfully popup
}
else {
print(statusCode)
}
}
})
}
This works fine ^^ .. I always receive the statuscode of 200. (If you wanted to try this you need to enable the insecure AppTransport)
And this is my PHP code.. I believe this doesn't work that properly..
<?php
$postVar = $_POST['data'];
if (!empty($postVar)) {
echo $postVar;
// email , subject, message
mail("myMail#mail.com","Agent was booked","The POST was set and button was pressed" . $postVar);
}
echo "doesn't work that good " . $postVar;
?>
I checked, it should be possible with my webhoster, to send emails..
But it doesn't work.. Did I forget something?
Well something must have gone really bad wrong... My whole dir was deleted while trying this.. :O
The directory /public_html does not exist or could not be selected, so
the directory / is shown instead.
well it probably didn't work that well.. My account was blocked...

Did you check the spam folder? Standard mail() function is not a great solution to send emails. Your mail provider can block email's sent from mail() or it just couldn't work at all. You need to send mail using smtp. Here's the example

Related

POST requests not working in Swift with Alamofire

I'm trying to send data from a Swift app to a backend in PHP.
To test, I make a request via POST with Alamofire and print the request method as a response from the Server.
let URL_USER = "myurl"
var sampleRequest = URLRequest(url: URL(string: URL_USER)!)
sampleRequest.httpMethod = HTTPMethod.post.rawValue
AF.request(sampleRequest).uploadProgress{ progress in }.response(){
response in
if(response.data != nil) {
print(String(bytes: response.data!, encoding: .utf8) as Any)
}
else {
print("Error")
}
}
The PHP script:
if ($_SERVER['REQUEST_METHOD'] == 'POST') {
echo 'OK';
}
else {
echo 'Wrong request method';
}
The server response is always Wrong request method
The same also occurs using the post parameter directly inside the Alamofire call, with this code:
AF.request("myurl", method: .post).response {...}
Any attempt to send the request via POST, even without Alamofire, fails and the server replies saying that the request is of type GET.
This occurs both on the simulator and on a real device, without any proxy.
The URL I call is based on https
UPDATE
To test the basic functioning of Alamofire with the function of their documentation I tried this code:
AF.request(URL_USER, method: .post).response {
response in
if(response.data != nil) {
print(String(bytes: response.data!, encoding: .utf8) as Any)
}
else {
print("Error")
}
}
But the response still goes Wrong request method and Proxyman says it's of type GET
The problem was caused by a redirect in the URL.
For some reason https://mysite.tld was redirecting to https://www.mysite.tld using GET. In this way all the parameters and the type of request were altered. I solved the problem by making the request directly to https://www.mysite.tld.
To find out the redirect I used Proxyman.

Swift HTTP Request Issue (Not sending HOST Header)

I have a simple rest endpoint built on PHP that works on postman and browsers.
https://someserver.com/api/endpoint.php?name=hello
But the code fails to execute when invoked from Swift.
Upon Investigation, I found out that Postman and Browser sends the Host Header whereas the Swift URLRequest doesn't. When you don't send the HOST Header, the php server refuses to accept the incoming request and I believe the request is rejected at the web server level. I tried using the
request.addValue("127.0.0.1", "Host")
but it still didn't work. Any help is appreciated.
Full Code (Swift 4)
let url = urlInput.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!
print("URL is: " + url)
var request = URLRequest(url: URL(string: url)!)
request.httpMethod = "GET"
request.addValue(<#T##value: String##String#>, forHTTPHeaderField: <#T##String#>)
let session = URLSession.shared
let task = session.dataTask(with: request, completionHandler: { data, response, error -> Void in
if let httpResponse = response as? HTTPURLResponse {
let respStr = String(data: data!, encoding: String.Encoding.utf8) as String?
print ("Response is \(respStr ?? "")")
print("statusCode: \(httpResponse.statusCode)")
let data: Data? = respStr?.data(using: .utf8)
}
})
Swift is ignoring the fact that you set the header, as it typically should. See the docs about Swift headers and why it's ignoring your Host header.
The URL Loading System handles various aspects of the HTTP protocol
for you (HTTP 1.1 persistent connections, proxies, authentication,
and so on). As part of this support, the URL Loading System takes
responsibility for certain HTTP headers:
Content-Length
Authorization
Connection
Host
Proxy-Authenticate
Proxy-Authorization
WWW-Authenticate
If you set a value for one of these reserved headers, the system may
ignore the value you set, or overwrite it with its own value, or
simply not send it. Moreover, the exact behavior may change over
time. To avoid confusing problems like this, do not set these headers
directly.
The documentation is here:
https://developer.apple.com/documentation/foundation/nsurlrequest#1776617
I have seen this before with Java - there is a workaround in Java depending on the library you are using, but I don't know about Swift.
I figured out that the issue happens only when you hit a php server. The php web server looks for some header and cant find it when the call is made from Swift. I even copied the working code from Postman and results were the same.
The solution I went with was to create a proxy server using firebase cloud function. Swift code would hit a firebase cloud function which talks to php and sends the response to swift.

retrofit2 sending a PUT request method is wrong for PHP

I am trying to send a PUT request method from my Android app to my PHP endpoint but in my endpoint the PUT request is not recognized as a PUT request so I return Request method is wrong! message from my endpoint.
Android interface and request execution
Interface for activation
#PUT("device/activate.php")
Call<DeviceRegistry> registryDevice();
Executing the request
DeviceRegistryAPI registryAPI =
RetrofitController.getRetrofit().create(DeviceRegistryAPI.class);
Call<DeviceRegistry> registryCallback = registryAPI.registryDevice();
response = registryCallback.execute();
With this I am expecting a response but I am getting my endpoint error message.
My PHP endpoint
if($_SERVER['REQUEST_METHOD'] == "PUT"){
//doing something with the data
} else {
$data = array("result" => 0, "message" => "Request method is wrong!");
}
I don't know why the $_SERVER['REQUEST_METHOD'] == "PUT" is false but I wonder if I am missing something on Retrofit 2.
More Info.
I am using Retrofit2.
Update 1: Sending json into the body
I am trying to send a json using the body.
It is my json:
{
"number": 1,
"infoList": [
{
"id": 1,
"info": "something"
},
{
"id": 2,
"info": "something"
}
]
}
There are my classes:
class DataInfo{
public int number;
public List<Info> infoList;
public DataInfo(int number, List<Info> list){
this.number = number;
this.infoList = list;
}
}
class Info{
public int id;
public String info;
}
I changed the PUT interface to this:
#PUT("device/activate.php")
Call<DeviceRegistry> registryDevice(#Body DataInfo info);
But I am getting the same problem.
Update 2: Do I need Header
I have this header in my REstfull client:
Accept: application/json
Content-Type: application/x-www-form-urlencoded
Do I need to put this on my request configuration? How do I do that if I need it?
Update 3: checking the request type of my sending post.
Now I am checking the type of the request. Because I am having the same problem with the PUT/POST requests. So If can solved the problem with the put maybe all the problems will be solved.
When I execute the request and asking and inspect the request it is sending the the type (PUT/POST) but in the server php only detect or GET?? (the below example is using POST and the behavior is the same)
Call<UpdateResponse> requestCall = client.updateMedia(downloadItemList);
Log.i("CCC", requestCall .request().toString());
And the output is a POST:
Request{method=POST, url=http://myserver/api/v1/media/updateMedia.php, tag=null}
so I am sending a POST (no matter if I send a PUT) request to the sever but why in the server I am receiving a GET. I am locked!!! I don't know where is the problem.
Update 4: godaddy hosting.
I have my php server hosting on godaddy. Is there any problem with that? I create a local host and everything works pretty good but the same code is not working on godaddy. I did some research but I didn't find any good answer to this problem so Is possible that godaddy hosting is the problem?
PHP doesn't recognize anything other than GET and POST. the server should throw at you some kind of error like empty request.
To access PUT and other requests use
$putfp = fopen('php://input', 'r'); //will be a JSON string (provided everything got sent)
$putdata = '';
while($data = fread($putfp, filesize('php://input')))
$putdata .= $data;
fclose($putfp);
//php-like variable, if you want
$_PUT = json_decode($putdata);
did not tested, but should work.
I guess the problem is that you don't pass any data along with PUT request, that's why PHP recognizes the request as a GET. So I think you just need to try to pass some data using #FormUrlEncoded, #Multipart or probably #Body annotations
To add header in your retrofit2 you should create an interceptor:
Interceptor interceptor = new Interceptor() {
#Override
public okhttp3.Response intercept(Interceptor.Chain chain) throws IOException
{
okhttp3.Request.Builder ongoing = chain.request().newBuilder();
ongoing.addHeader("Content-Type", "application/x-www-form-urlencoded");
ongoing.addHeader("Accept", "application/json");
return chain.proceed(ongoing.build());
}
};
and add it to your client builder:
OkHttpClient.Builder builder = new OkHttpClient.Builder();
builder.interceptors().add(interceptor);
PHP recognises 'PUT' calls. Extracted from PHP.net:
'REQUEST_METHOD' Which request method was used to access the page;
i.e. 'GET', 'HEAD', 'POST', 'PUT'.
You don't need to send any header if your server isn't expecting any
header.
Prior to use Retrofit or any other networking library, you should check the endpoint using a request http builder, like Postman or Advanced Rest Client. To debug the request/response when running your app or unit tests use a proxy like Charles, it will help you a lot to watch how your request/response really looks.

Make contact form for iOS app with Swift and PHP

I want to create a contact form where the user can leave me a message (and name and phone number…) and send it to me.
But I don't know how to do this because I never dealt with thinks like this before.
My own suggestion is to $_POST the content from TextField and TextView to a PHP script on my server. This will handle the content. (Either send an email to me with mail() or store it in a file on the server. The PHP script is no problem for me.)
Is that way reasonable? What is the common way to do that, to leave a feedback or something like this to the developer?
P.S. I know there's a way that the user sends me an email from inside the app. But I don't like this way.
That seems reasonable to me. You could just write a function in swift to send to send get or post parameters like so:
func postParamRequest(resourceURL: String, postData: String, completionHandler: ((NSURLResponse?, NSData?, NSError?) -> Void)) {
let request : NSMutableURLRequest = NSMutableURLRequest()
request.URL = NSURL(string: resourceURL)
request.HTTPMethod = "POST"
request.setValue("application/x-www-form-urlencoded; charset=utf-8", forHTTPHeaderField: "Content-Type")
request.HTTPBody = postData.dataUsingEncoding(NSUTF8StringEncoding)
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue(), completionHandler:{ (response:NSURLResponse?, data: NSData?, error: NSError?) in
completionHandler(response, data, error)
})
}
You can then just call that function and get the callback of the response, data, and any errors too (the postData should be [key: value]) for the POST parameters. Like so:
postParamRequest("theUrlToYourScript", postData: "key1=value&key2=value&key3=value") { (response, data, error) in
print(data)
}
In your PHP script you could then retrieve the data with something like this: $_POST["paramName"].

Sending a request to a php web service from iOS

I have a question relating to sending a POST request from an iOS app to a web service written in php, that will ultimately query a MySQL database.
tldr: How do I view the contents of the POST variables directly in the browser window, without refreshing?
Long version:
I had written my Swift code in Xcode, with NSURLSession, request, data etc.
I had a php web page set to var_dump($_POST); so that I could check that the data was sent in correctly (my data was a hard-coded string in Xcode for testing purposes).
I couldn't for the life of me figure out why I kept getting empty POST variables, until I decided to add a test query statement to my web page binding the POST variable. Lo and behold, the query ran successfully and my table updated.
I now realise that the reason I thought the POST variable was empty was because I was refreshing the web page in order to see the results of my var_dump. I now also know that this was deleting the POST data, because when I repeated this action with the query statement, my table was getting NULL rows.
My question is how do I view the contents of the POST variables directly in the browser window, without refreshing? I know this must be a real noob goose chase I've led myself on... but I am a noob.
Thank you
You would need to modify the service itself to output those values in some way. If this is strictly for debugging, you are better off having the service write out to a log file instead. If this is part of the requesting applications call and the data needs to be displayed to the user, the service should probably return either an XML or JSON string response that your application can parse. Otherwise, you can use Fiddler to monitor your web traffic.
Of course overtime you refresh the page you just get an empty variable.
This is what I used to test if my code was working:
func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool {
// Override point for customization after application launch.
testPost() // this function will test that the code is sending the variable to your server
return true
}
func testPost() {
let variableToPost = "someVariable"
let myUrl = NSURL(string: "http://www.yourserver.com/api/v1.0/post.php")
let request = NSMutableURLRequest(URL: myUrl!)
request.HTTPMethod = "POST"
let postString = "variable=\(variableToPost)"
request.HTTPBody = postString.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: true)
let task = NSURLSession.sharedSession().dataTaskWithRequest(request)
{ data, response, error in
if error != nil {
print(error)
return
}
do{
let json = try NSJSONSerialization.JSONObjectWithData(data!, options: .MutableContainers) as? NSDictionary
if let parseJSON = json{
let result = parseJSON["status"] as? String
let message = parseJSON["message"] as? String
if result == "Success"{
//this should return your variable
print(message)
}else{
// print the message if it failed ie. Missing required field
print(message)
}
}//if parse
} catch let error as NSError {
print("error in registering: \(error)")
} //catch
}
task.resume()
}
then your php file will only check if there is no empty post and return the variable as JSON:
post.php
<?php
$postValue = htmlentities($_POST["variable"]);
if(empty($postValue))
{
$returnValue["status"] = "error";
$returnValue["message"] = "Missing required field";
echo json_encode($returnValue);
return;
} else {
$returnValue["status"] = "success";
$returnValue["message"] = "your post value is ".$postValue."";
echo json_encode($returnValue);
}

Categories