1

I am trying to securely send data from an activity of my android application to a php script on a remote server. When I start the application, the application is not crashing nor am I prompted any error message in the console. However the data do not seem to be sent to the php script.

I have tried to narrow down the lines where the error could occur by adding Log.d(...) commands between each line. When I run the application in debug mode, every Log.d(...) is printed to the console, so I expected the php script to be incorrect. However, further investigation has shown the data do not arrive at the php script, since $score = $_POST["score"] is not containing the expected value. Also, if I arbitrarily change the url for the request and start the application again, no error message occurs either. So I expect that the error lies somewhere between url.openConnection() and urlConnection.connect() in the MyActivity.kt file.

Question

Why is the code not sending the data to the script and how can I fix it?

class MyActivity : AppCompatActivity() {

    override fun onCreate(savedInstanceState: Bundle?) {
        ...
        this.configureNetworkRunnable()
    }
   
    private fun configureNetworkRunnable() {
        Thread( Runnable {
            uploadData()
        }).start()
    }

    private fun uploadData() {
        val charset = "UTF-8"
        val parameter = URLEncoder.encode("param1", charset) + "=" + URLEncoder.encode("20", charset)

        val url = URL("https://www.myurl.com/path/file.php")
        val urlConnection = url.openConnection()
        urlConnection.setDoOutput(true)

        val outputStream: OutputStream = urlConnection.getOutputStream()
        outputStream.write(parameter.toByteArray(Charsets.UTF_8))
        urlConnection.connect()
    }
}

GameActivity.kt

<?php
    $param1 = $_POST["param1"];
    ...

file.php

D/NetworkSecurityConfig: No Network Security Config specified, using platform default
D/OpenGLRenderer: makeCurrent EglSurface : 0x7cf3783000 -> 0x7cf3783b00
D/ViewRootImpl@1b125bd[GameActivity]: MSG_RESIZED: frame=(112,0,2280,1080) ci=(0,0,0,0) vi=(0,0,0,0) or=2
I/System.out: (HTTPLog)-Static: isSBSettingEnabled false
I/System.out: (HTTPLog)-Static: isSBSettingEnabled false
D/TcpOptimizer: TcpOptimizer-ON
D/libmdf: libmdf v2.9.0.0 On 64bit PLATFORM
D/OpenGLRenderer: destroyEglSurface : 0x7cf3783000
I/mali_egl: eglDestroySurface() in
I/mali_winsys: delete_surface() [2168x1080] return
I/mali_egl: eglDestroySurface() out
W/libEGL: EGLNativeWindowType 0x7d82347810 disconnect failed
D/OpenGLRenderer: ~ReliableSurface : 0x7d82347800
D/ViewRootImpl@fc1415c[MainActivity]: Relayout returned: old=(112,0,2280,1080) new=(112,0,2280,1080) req=(2168,1080)8 dur=10 res=0x5 s={false 0} ch=true
D/ViewRootImpl@fc1415c[MainActivity]: stopped(true) old=false
V/ViewRootImpl@fc1415c[MainActivity]: updateAppliedLetterboxDirection, direction=0, Caller=android.view.ViewRootImpl.handleDispatchLetterboxDirectionChanged:8044

console

Thank you in advance.

ingoBe
  • 57
  • 6

1 Answers1

1

As the protocol of that URL is "https", cast that URLConnection to HttpsURLConnection. Then, since we're sending data, set the request method to "POST". We'll also set the content-type of the data we're sending so our script knows what to expect. So the construction of this HttpsURLConnection should look like:

val urlConnection = url.openConnection() as HttpsURLConnection
urlConnection.apply {
  requestMethod = "POST"
  doOutput = true
  setRequestProperty("Content-Type", "application/octet-stream")
}

It also doesn't look like you're properly closing your stream after sending the data. Try:

urlConnection.outputStream.use { stream ->
  stream.write("20".toByteArray(Charsets.UTF_8))
}

which will write the bytes to your stream and handle closing it for you, exception or not.

Finally, you have to read the inputStream fully, so try:

urlConnection.inputStream.bufferedReader().use {
  it.readText()
}

If you're still experiencing issues, print to log your urlConnection.responseCode and optionally that it.readText() for me.

kabumere
  • 353
  • 2
  • 8
  • Thank you! I have applied your suggested code. ``ìt.readText()``` prints my echo. So, the connection is established, but it seems, that the value transfer doesn't work, because the param1 from the php file is 0. responseCode: 200. Is it mandatory to read the inputStream here, or is it only for debugging purposes? Thank you in advance! – ingoBe Aug 07 '20 at 00:12
  • @ingoBe I'm not too familiar with PHP, but we're writing the bytes in the request body here (not as a value to a query param) so try using [this answer](https://stackoverflow.com/a/8945912/14032472) in order to read the POST body in your php script. Be sure to convert the bytes back into a string using the proper charset/encoding within your script. – kabumere Aug 07 '20 at 00:21
  • Also, from my recollection, you HAVE to read the input stream fully when sending data through a URLConnection. It's not just for debugging purposes. **EDIT:** https://stackoverflow.com/a/4844926/14032472 – kabumere Aug 07 '20 at 00:23
  • Ah, sorry, I'm seeing how you were trying to use `parameter` now. Will the data you're sending always be a string? Or can it at any point be arbitrary binary data? – kabumere Aug 07 '20 at 00:29
  • Thanks! Up to now binary data would be possible, but later I probably have to send strings as well. That is why I did it from the beginning. – ingoBe Aug 07 '20 at 00:34
  • So in your example, `"20"` would be the data you wanted stored as `param1`, correct? Change `parameter.toByteArray(Charsets.UTF_8)` to `"20".toByteArray(Charsets.UTF_8)`, then follow the link I posted earlier on how to read POST bodies in PHP. You should have access to it now. – kabumere Aug 07 '20 at 00:36
  • It works! The php script receives the data as expected. Thank you very much for your effort! :) – ingoBe Aug 07 '20 at 00:44