Intercepting Collect submissions with PHP

Hi, we've been trying to implement a PHP script which accepts requests from Collect and sends them to Aggregate. The reason why we are doing this is because we need to restrict which user can see which forms, something that isn't possible with Aggregate. So far, we've been able to implement the user login and the forms list through /formList. We are trying to implement form submission (/submission), but we are struggling with the PHP code. It appears that the API used to submit data is not really documented and doesn't appear to follow the OpenRosa standard described here:

https://bitbucket.org/javarosa/javarosa/wiki/FormSubmissionAPI

The code in Collect:

https://code.google.com/p/opendatakit/source/browse/src/org/odk/collect/android/tasks/InstanceUploaderTask.java?repo=collect

Seems to indicate that the communication between Collect and Aggregate relies on a 204 http response which is not mentioned in the OpenRosa standards. Also, it seems to also require a Location: in the header, which is contradictory with the "204 No Content" response. In PHP, issuing a Location in the header automatically converts the response into a 301 or 302 and ignores the 204.

Does anybody have a functioning PHP code sample to intercept data sent from Collect?

I tried to use other PHP code samples posted in previous threads, but they appear to only issue a 204 reponse with no Location, which doesn't appear to work in recent versions of Collect.

Thank you very much,

Guillaume

I've answered my own question shortly after posting this. It looks like you can trick PHP into issuing 204 response while having a Location in the header with this simple command:

header("Location: http://myserver.com/odk/",true,204);

I'm now able to intercept the posted files and send them to Agggregate.

Cheers,

Guillaume

··· On Monday, June 8, 2015 at 12:55:30 PM UTC-4, gla...@gmail.com wrote: > Hi, we've been trying to implement a PHP script which accepts requests from Collect and sends them to Aggregate. The reason why we are doing this is because we need to restrict which user can see which forms, something that isn't possible with Aggregate. So far, we've been able to implement the user login and the forms list through /formList. We are trying to implement form submission (/submission), but we are struggling with the PHP code. It appears that the API used to submit data is not really documented and doesn't appear to follow the OpenRosa standard described here: > > https://bitbucket.org/javarosa/javarosa/wiki/FormSubmissionAPI > > The code in Collect: > > https://code.google.com/p/opendatakit/source/browse/src/org/odk/collect/android/tasks/InstanceUploaderTask.java?repo=collect > > Seems to indicate that the communication between Collect and Aggregate relies on a 204 http response which is not mentioned in the OpenRosa standards. Also, it seems to also require a Location: in the header, which is contradictory with the "204 No Content" response. In PHP, issuing a Location in the header automatically converts the response into a 301 or 302 and ignores the 204. > > Does anybody have a functioning PHP code sample to intercept data sent from Collect? > > I tried to use other PHP code samples posted in previous threads, but they appear to only issue a 204 reponse with no Location, which doesn't appear to work in recent versions of Collect. > > Thank you very much, > > Guillaume

Can someone please share the PHP working code the accepts form substitutions and put them into my sql database...

Thank you

··· On Monday, June 8, 2015 at 7:55:30 PM UTC+3, gla...@gmail.com wrote: > Hi, we've been trying to implement a PHP script which accepts requests from Collect and sends them to Aggregate. The reason why we are doing this is because we need to restrict which user can see which forms, something that isn't possible with Aggregate. So far, we've been able to implement the user login and the forms list through /formList. We are trying to implement form submission (/submission), but we are struggling with the PHP code. It appears that the API used to submit data is not really documented and doesn't appear to follow the OpenRosa standard described here: > > https://bitbucket.org/javarosa/javarosa/wiki/FormSubmissionAPI > > The code in Collect: > > https://code.google.com/p/opendatakit/source/browse/src/org/odk/collect/android/tasks/InstanceUploaderTask.java?repo=collect > > Seems to indicate that the communication between Collect and Aggregate relies on a 204 http response which is not mentioned in the OpenRosa standards. Also, it seems to also require a Location: in the header, which is contradictory with the "204 No Content" response. In PHP, issuing a Location in the header automatically converts the response into a 301 or 302 and ignores the 204. > > Does anybody have a functioning PHP code sample to intercept data sent from Collect? > > I tried to use other PHP code samples posted in previous threads, but they appear to only issue a 204 reponse with no Location, which doesn't appear to work in recent versions of Collect. > > Thank you very much, > > Guillaume

The 204 is expected to be returned in response to a HEAD request from ODK
Collect.

Every submission starts with a HEAD request followed by a POST.

This is done to (a) detect network login pages and (b) negotiate
authentication credentials prior to issuing the large POST of data when
submitting.

··· On Mon, Jun 8, 2015 at 10:42 AM, wrote:

I've answered my own question shortly after posting this. It looks like
you can trick PHP into issuing 204 response while having a Location in the
header with this simple command:

header("Location: http://myserver.com/odk/",true,204);

I'm now able to intercept the posted files and send them to Agggregate.

Cheers,

Guillaume

On Monday, June 8, 2015 at 12:55:30 PM UTC-4, gla...@gmail.com wrote:

Hi, we've been trying to implement a PHP script which accepts requests
from Collect and sends them to Aggregate. The reason why we are doing this
is because we need to restrict which user can see which forms, something
that isn't possible with Aggregate. So far, we've been able to implement
the user login and the forms list through /formList. We are trying to
implement form submission (/submission), but we are struggling with the PHP
code. It appears that the API used to submit data is not really documented
and doesn't appear to follow the OpenRosa standard described here:

https://bitbucket.org/javarosa/javarosa/wiki/FormSubmissionAPI

The code in Collect:

https://code.google.com/p/opendatakit/source/browse/src/org/odk/collect/android/tasks/InstanceUploaderTask.java?repo=collect

Seems to indicate that the communication between Collect and Aggregate
relies on a 204 http response which is not mentioned in the OpenRosa
standards. Also, it seems to also require a Location: in the header, which
is contradictory with the "204 No Content" response. In PHP, issuing a
Location in the header automatically converts the response into a 301 or
302 and ignores the 204.

Does anybody have a functioning PHP code sample to intercept data sent
from Collect?

I tried to use other PHP code samples posted in previous threads, but
they appear to only issue a 204 reponse with no Location, which doesn't
appear to work in recent versions of Collect.

Thank you very much,

Guillaume

--
You received this message because you are subscribed to the Google Groups
"ODK Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to opendatakit-developers+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
Mitch Sundt
Software Engineer
University of Washington
mitchellsundt@gmail.com

Here is code for a formList/index.php file that will intercept Collect submissions, validate the login and password of the user, and only show forms submitted by this user. Note that this is in PostgreSQL, not MySQL.

$error = false;
$elog = "";

if (empty($_SERVER['PHP_AUTH_DIGEST'])){ // before credentials

http_response_code(401);
header("HTTP/1.1 401 Unauthorized");
header('Content-Type: text/xml; charset=utf-8');
header('WWW-Authenticate: Digest realm="**INSERT YOUR REALM HERE**",qop="auth",nonce="'.uniqid().'",opaque="'.md5('**INSERT YOUR REALM HERE**').'"');
header('"HTTP_X_OPENROSA_VERSION": "1.0"');
header('X-OpenRosa-Version:1.0');

} else { // after credentials

header('Content-Type: text/xml; charset=utf-8');
header('"HTTP_X_OPENROSA_VERSION": "1.0"');
header('X-OpenRosa-Version:1.0');

$uid=check_user_pass();	
if ($uid!==false){
    echo '<xforms xmlns="http://openrosa.org/xforms/xformsList">';
    $uid = pg_escape_literal($uid);
    $query = 'SELECT * FROM odk_prod._form_info WHERE "_CREATOR_URI_USER" = '.$uid.' AND "_IS_COMPLETE" = TRUE';
    $result = pg_query($con_pg, $query);
    if (!$result) { 
        $error = true;
    } else {
        while ($row = pg_fetch_assoc($result)) {
            $form = $row["FORM_ID"];
            $query = 'SELECT "FORM_NAME", "ROOT_ELEMENT_MODEL_VERSION" FROM odk_prod._form_info_fileset WHERE "_TOP_LEVEL_AURI" = \''.$row['_URI'].'\'';
            $result_ref = pg_query($con_pg,$query);
            $row_ref=pg_fetch_assoc($result_ref);
            echo '<xform>';
            echo '<formID>'.$form.'</formID>';
            echo '<name>'.$row_ref['FORM_NAME'].'</name>';
            echo '<majorMinorVersion>'.$row_ref['ROOT_ELEMENT_MODEL_VERSION'].'</majorMinorVersion>';
            echo '<version>'.$row_ref['ROOT_ELEMENT_MODEL_VERSION'].'</version>';
            echo '<hash>'.$row['_URI'].'</hash>';
            echo '<downloadUrl>http://quebio.ca/odk/formXML/?formId='.$form.'</downloadUrl>';
            $query = 'SELECT * FROM odk_prod._form_info_manifest_bin WHERE "_TOP_LEVEL_AURI" = \''.$row['_URI'].'\'';
            $result2 = pg_query($con_pg, $query);
            if (pg_num_rows($result2)>0){
            echo '<manifestUrl>http://**YOUR_SERVER_ADDRESS**/formList/xformsManifest.php?formId='.$form.'</manifestUrl>';
            }
            echo '</xform>';
        }
    }
    echo '</xforms>';
}

}

function check_user_pass() {
$data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST']);
$name = $data['username'];
$error=false;
// double check connection
if (!$con_pg) {
$error = true;
}

// query db for hashed password for given username
if (!$error){
    $name = pg_escape_literal($name);
    $query = 'SELECT * FROM odk_prod._registered_users WHERE "LOCAL_USERNAME" = '.$name.' AND "IS_REMOVED" = FALSE';
    $result = pg_query($con_pg, $query);
    if (!$result) {
        $error = true;
    } else {
        while ($row = pg_fetch_assoc($result)) {
          $pwd = $row["DIGEST_AUTH_PASSWORD"]; //hashed password
          $uid = $row["_URI"]; //uid used in other tables
        }
    }
}

if (!$error){
    $A1 = $pwd;
    $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);
    $valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);
    if ($data['response'] != $valid_response){
        $error = true;
    }
}
if (!$error){
    return $uid;
}else{
    return false;   
}    

}

··· On Wednesday, September 2, 2015 at 2:10:06 PM UTC-4, darub...@gmail.com wrote: > Can someone please share the PHP working code the accepts form substitutions and put them into my sql database... > > Thank you > > On Monday, June 8, 2015 at 7:55:30 PM UTC+3, gla...@gmail.com wrote: > > Hi, we've been trying to implement a PHP script which accepts requests from Collect and sends them to Aggregate. The reason why we are doing this is because we need to restrict which user can see which forms, something that isn't possible with Aggregate. So far, we've been able to implement the user login and the forms list through /formList. We are trying to implement form submission (/submission), but we are struggling with the PHP code. It appears that the API used to submit data is not really documented and doesn't appear to follow the OpenRosa standard described here: > > > > https://bitbucket.org/javarosa/javarosa/wiki/FormSubmissionAPI > > > > The code in Collect: > > > > https://code.google.com/p/opendatakit/source/browse/src/org/odk/collect/android/tasks/InstanceUploaderTask.java?repo=collect > > > > Seems to indicate that the communication between Collect and Aggregate relies on a 204 http response which is not mentioned in the OpenRosa standards. Also, it seems to also require a Location: in the header, which is contradictory with the "204 No Content" response. In PHP, issuing a Location in the header automatically converts the response into a 301 or 302 and ignores the 204. > > > > Does anybody have a functioning PHP code sample to intercept data sent from Collect? > > > > I tried to use other PHP code samples posted in previous threads, but they appear to only issue a 204 reponse with no Location, which doesn't appear to work in recent versions of Collect. > > > > Thank you very much, > > > > Guillaume

Maybe I'm not understanding this correctly, but if the HEAD request expects a Location back, shouldn't the response from the server be a 301 instead of a 204?

··· On Monday, June 8, 2015 at 3:37:25 PM UTC-4, Mitch wrote: > The 204 is expected to be returned in response to a HEAD request from ODK Collect. > > Every submission starts with a HEAD request followed by a POST. > > > This is done to (a) detect network login pages and (b) negotiate authentication credentials prior to issuing the large POST of data when submitting. > > > > > On Mon, Jun 8, 2015 at 10:42 AM, wrote: > I've answered my own question shortly after posting this. It looks like you can trick PHP into issuing 204 response while having a Location in the header with this simple command: > > > > header("Location: http://myserver.com/odk/",true,204); > > > > I'm now able to intercept the posted files and send them to Agggregate. > > > > Cheers, > > > > Guillaume > > > > > > On Monday, June 8, 2015 at 12:55:30 PM UTC-4, gla...@gmail.com wrote: > > > Hi, we've been trying to implement a PHP script which accepts requests from Collect and sends them to Aggregate. The reason why we are doing this is because we need to restrict which user can see which forms, something that isn't possible with Aggregate. So far, we've been able to implement the user login and the forms list through /formList. We are trying to implement form submission (/submission), but we are struggling with the PHP code. It appears that the API used to submit data is not really documented and doesn't appear to follow the OpenRosa standard described here: > > > > > > https://bitbucket.org/javarosa/javarosa/wiki/FormSubmissionAPI > > > > > > The code in Collect: > > > > > > https://code.google.com/p/opendatakit/source/browse/src/org/odk/collect/android/tasks/InstanceUploaderTask.java?repo=collect > > > > > > Seems to indicate that the communication between Collect and Aggregate relies on a 204 http response which is not mentioned in the OpenRosa standards. Also, it seems to also require a Location: in the header, which is contradictory with the "204 No Content" response. In PHP, issuing a Location in the header automatically converts the response into a 301 or 302 and ignores the 204. > > > > > > Does anybody have a functioning PHP code sample to intercept data sent from Collect? > > > > > > I tried to use other PHP code samples posted in previous threads, but they appear to only issue a 204 reponse with no Location, which doesn't appear to work in recent versions of Collect. > > > > > > Thank you very much, > > > > > > Guillaume > > > > -- > > You received this message because you are subscribed to the Google Groups "ODK Developers" group. > > To unsubscribe from this group and stop receiving emails from it, send an email to opendatakit-developers+unsubscribe@googlegroups.com. > > For more options, visit https://groups.google.com/d/optout. > > > > > -- > > Mitch Sundt > Software Engineer > University of Washington > mitche...@gmail.com

Here is code for a formList/index.php file that will intercept Collect submissions, validate the login and password of the user, and only show forms submitted by this user. Note that this is in PostgreSQL, not MySQL.

$error = false;
$elog = "";

if (empty($_SERVER['PHP_AUTH_DIGEST'])){ // before credentials

http_response_code(401);
header("HTTP/1.1 401 Unauthorized");
header('Content-Type: text/xml; charset=utf-8');
header('WWW-Authenticate: Digest realm="INSERT YOUR REALM HERE",qop="auth",nonce="'.uniqid().'",opaque="'.md5('INSERT YOUR REALM HERE').'"');
header('"HTTP_X_OPENROSA_VERSION": "1.0"');
header('X-OpenRosa-Version:1.0');

} else { // after credentials

header('Content-Type: text/xml; charset=utf-8');
header('"HTTP_X_OPENROSA_VERSION": "1.0"');
header('X-OpenRosa-Version:1.0');

$uid=check_user_pass();	
if ($uid!==false){
    echo '<xforms xmlns="http://openrosa.org/xforms/xformsList">';
    $uid = pg_escape_literal($uid);
    $query = 'SELECT * FROM odk_prod._form_info WHERE "_CREATOR_URI_USER" = '.$uid.' AND "_IS_COMPLETE" = TRUE';
    $result = pg_query($con_pg, $query);
    if (!$result) { 
        $error = true;
    } else {
        while ($row = pg_fetch_assoc($result)) {
            $form = $row["FORM_ID"];
            $query = 'SELECT "FORM_NAME", "ROOT_ELEMENT_MODEL_VERSION" FROM odk_prod._form_info_fileset WHERE "_TOP_LEVEL_AURI" = \''.$row['_URI'].'\'';
            $result_ref = pg_query($con_pg,$query);
            $row_ref=pg_fetch_assoc($result_ref);
            echo '<xform>';
            echo '<formID>'.$form.'</formID>';
            echo '<name>'.$row_ref['FORM_NAME'].'</name>';
            echo '<majorMinorVersion>'.$row_ref['ROOT_ELEMENT_MODEL_VERSION'].'</majorMinorVersion>';
            echo '<version>'.$row_ref['ROOT_ELEMENT_MODEL_VERSION'].'</version>';
            echo '<hash>'.$row['_URI'].'</hash>';
            echo '<downloadUrl>http://quebio.ca/odk/formXML/?formId='.$form.'</downloadUrl>';
            $query = 'SELECT * FROM odk_prod._form_info_manifest_bin WHERE "_TOP_LEVEL_AURI" = \''.$row['_URI'].'\'';
            $result2 = pg_query($con_pg, $query);
            if (pg_num_rows($result2)>0){
            echo '<manifestUrl>http://**YOUR_SERVER_ADDRESS**/formList/xformsManifest.php?formId='.$form.'</manifestUrl>';
            }
            echo '</xform>';
        }
    }
    echo '</xforms>';
}

}

function check_user_pass() {
$data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST']);
$name = $data['username'];
$error=false;
// double check connection
if (!$con_pg) {
$error = true;
}

// query db for hashed password for given username
if (!$error){
    $name = pg_escape_literal($name);
    $query = 'SELECT * FROM odk_prod._registered_users WHERE "LOCAL_USERNAME" = '.$name.' AND "IS_REMOVED" = FALSE';
    $result = pg_query($con_pg, $query);
    if (!$result) {
        $error = true;
    } else {
        while ($row = pg_fetch_assoc($result)) {
          $pwd = $row["DIGEST_AUTH_PASSWORD"]; //hashed password
          $uid = $row["_URI"]; //uid used in other tables
        }
    }
}

if (!$error){
    $A1 = $pwd;
    $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);
    $valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);
    if ($data['response'] != $valid_response){
        $error = true;
    }
}
if (!$error){
    return $uid;
}else{
    return false;   
}    

}

Can someone please share the PHP working code the accepts form substitutions and put them into my sql database...

Thank you

Hi, we've been trying to implement a PHP script which accepts requests from Collect and sends them to Aggregate. The reason why we are doing this is because we need to restrict which user can see which forms, something that isn't possible with Aggregate. So far, we've been able to implement the user login and the forms list through /formList. We are trying to implement form submission (/submission), but we are struggling with the PHP code. It appears that the API used to submit data is not really documented and doesn't appear to follow the OpenRosa standard described here:

https://bitbucket.org/javarosa/javarosa/wiki/FormSubmissionAPI

The code in Collect:

https://code.google.com/p/opendatakit/source/browse/src/org/odk/collect/android/tasks/InstanceUploaderTask.java?repo=collect

Seems to indicate that the communication between Collect and Aggregate relies on a 204 http response which is not mentioned in the OpenRosa standards. Also, it seems to also require a Location: in the header, which is contradictory with the "204 No Content" response. In PHP, issuing a Location in the header automatically converts the response into a 301 or 302 and ignores the 204.
Hi ...has this worked for anyone?

Does anybody have a functioning PHP code sample to intercept data sent from Collect?

I tried to use other PHP code samples posted in previous threads, but they appear to only issue a 204 reponse with no Location, which doesn't appear to work in recent versions of Collect.

Thank you very much,

Guillaume

··· On Wednesday, September 2, 2015 at 9:59:20 PM UTC+3, gla...@gmail.com wrote: > On Wednesday, September 2, 2015 at 2:10:06 PM UTC-4, darub...@gmail.com wrote: > > On Monday, June 8, 2015 at 7:55:30 PM UTC+3, gla...@gmail.com wrote:

Here's the history on why:

The 201/204 and the Location header were both attempts to detect Network
login screens. The Location header was the first attempt at this.

The current ODK Collect makes the Location header optional -- if supplied,
it can be used to redirect the submission path (/submission) to a different
path on the same server (or to a different scheme (e.g., https://); ODK
Collect does not allow a server to redirect to a different server URL.

ODK Aggregate always returns the .../submission URL as the Location, even
on a POST (and ODK Collect only processes the Location header on the HEAD
request). Returning this Location in response to a POST is not
expected/conformant REST behavior (it should return the download URL for
accessing the posted submission).

We then switched to the non-standard 201 return code to indicate a
successful interaction with the server and added the HEAD request to
confirm the scheme and authentication before the POST (so we never send
data over http unless the server accepts that, and we always have valid
authentication before sending large payloads to the server).

The question then became what to return from the initial HEAD request. We
can't determine the appropriate response from a HEAD request because the
response code is dependent upon the entity, and the HEAD request doesn't
contain one. So we settled on the 204 response, as the normal 201 response
does have an entity body which contains an XML response entity holding
information about the submission.

··· On Mon, Jun 8, 2015 at 12:51 PM, wrote:

Maybe I'm not understanding this correctly, but if the HEAD request
expects a Location back, shouldn't the response from the server be a 301
instead of a 204?

On Monday, June 8, 2015 at 3:37:25 PM UTC-4, Mitch wrote:

The 204 is expected to be returned in response to a HEAD request from
ODK Collect.

Every submission starts with a HEAD request followed by a POST.

This is done to (a) detect network login pages and (b) negotiate
authentication credentials prior to issuing the large POST of data when
submitting.

On Mon, Jun 8, 2015 at 10:42 AM, gla...@gmail.com wrote:
I've answered my own question shortly after posting this. It looks like
you can trick PHP into issuing 204 response while having a Location in the
header with this simple command:

header("Location: http://myserver.com/odk/",true,204);

I'm now able to intercept the posted files and send them to Agggregate.

Cheers,

Guillaume

On Monday, June 8, 2015 at 12:55:30 PM UTC-4, gla...@gmail.com wrote:

Hi, we've been trying to implement a PHP script which accepts requests
from Collect and sends them to Aggregate. The reason why we are doing this
is because we need to restrict which user can see which forms, something
that isn't possible with Aggregate. So far, we've been able to implement
the user login and the forms list through /formList. We are trying to
implement form submission (/submission), but we are struggling with the PHP
code. It appears that the API used to submit data is not really documented
and doesn't appear to follow the OpenRosa standard described here:

https://bitbucket.org/javarosa/javarosa/wiki/FormSubmissionAPI

The code in Collect:

https://code.google.com/p/opendatakit/source/browse/src/org/odk/collect/android/tasks/InstanceUploaderTask.java?repo=collect

Seems to indicate that the communication between Collect and Aggregate
relies on a 204 http response which is not mentioned in the OpenRosa
standards. Also, it seems to also require a Location: in the header, which
is contradictory with the "204 No Content" response. In PHP, issuing a
Location in the header automatically converts the response into a 301 or
302 and ignores the 204.

Does anybody have a functioning PHP code sample to intercept data sent
from Collect?

I tried to use other PHP code samples posted in previous threads, but
they appear to only issue a 204 reponse with no Location, which doesn't
appear to work in recent versions of Collect.

Thank you very much,

Guillaume

--

You received this message because you are subscribed to the Google
Groups "ODK Developers" group.

To unsubscribe from this group and stop receiving emails from it, send
an email to opendatakit-developers+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--

Mitch Sundt
Software Engineer
University of Washington
mitche...@gmail.com

--
You received this message because you are subscribed to the Google Groups
"ODK Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to opendatakit-developers+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
Mitch Sundt
Software Engineer
University of Washington
mitchellsundt@gmail.com

It works for us...

··· On Wednesday, February 3, 2016 at 1:24:35 PM UTC-5, krcsde...@gmail.com wrote: > On Wednesday, September 2, 2015 at 9:59:20 PM UTC+3, gla...@gmail.com wrote: > > Here is code for a formList/index.php file that will intercept Collect submissions, validate the login and password of the user, and only show forms submitted by this user. Note that this is in PostgreSQL, not MySQL. > > > > $error = false; > > $elog = ""; > > > > if (empty($_SERVER['PHP_AUTH_DIGEST'])){ // before credentials > > > > http_response_code(401); > > header("HTTP/1.1 401 Unauthorized"); > > header('Content-Type: text/xml; charset=utf-8'); > > header('WWW-Authenticate: Digest realm="**INSERT YOUR REALM HERE**",qop="auth",nonce="'.uniqid().'",opaque="'.md5('**INSERT YOUR REALM HERE**').'"'); > > header('"HTTP_X_OPENROSA_VERSION": "1.0"'); > > header('X-OpenRosa-Version:1.0'); > > > > } else { // after credentials > > > > header('Content-Type: text/xml; charset=utf-8'); > > header('"HTTP_X_OPENROSA_VERSION": "1.0"'); > > header('X-OpenRosa-Version:1.0'); > > > > $uid=check_user_pass(); > > if ($uid!==false){ > > echo ''; > > $uid = pg_escape_literal($uid); > > $query = 'SELECT * FROM odk_prod._form_info WHERE "_CREATOR_URI_USER" = '.$uid.' AND "_IS_COMPLETE" = TRUE'; > > $result = pg_query($con_pg, $query); > > if (!$result) { > > $error = true; > > } else { > > while ($row = pg_fetch_assoc($result)) { > > $form = $row["FORM_ID"]; > > $query = 'SELECT "FORM_NAME", "ROOT_ELEMENT_MODEL_VERSION" FROM odk_prod._form_info_fileset WHERE "_TOP_LEVEL_AURI" = \''.$row['_URI'].'\''; > > $result_ref = pg_query($con_pg,$query); > > $row_ref=pg_fetch_assoc($result_ref); > > echo ''; > > echo ''.$form.''; > > echo ''.$row_ref['FORM_NAME'].''; > > echo ''.$row_ref['ROOT_ELEMENT_MODEL_VERSION'].''; > > echo ''.$row_ref['ROOT_ELEMENT_MODEL_VERSION'].''; > > echo ''.$row['_URI'].''; > > echo 'http://quebio.ca/odk/formXML/?formId='.$form.''; > > $query = 'SELECT * FROM odk_prod._form_info_manifest_bin WHERE "_TOP_LEVEL_AURI" = \''.$row['_URI'].'\''; > > $result2 = pg_query($con_pg, $query); > > if (pg_num_rows($result2)>0){ > > echo 'http://**YOUR_SERVER_ADDRESS**/formList/xformsManifest.php?formId='.$form.''; > > } > > echo ''; > > } > > } > > echo ''; > > } > > } > > > > > > function check_user_pass() { > > $data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST']); > > $name = $data['username']; > > $error=false; > > // double check connection > > if (!$con_pg) { > > $error = true; > > } > > > > // query db for hashed password for given username > > if (!$error){ > > $name = pg_escape_literal($name); > > $query = 'SELECT * FROM odk_prod._registered_users WHERE "LOCAL_USERNAME" = '.$name.' AND "IS_REMOVED" = FALSE'; > > $result = pg_query($con_pg, $query); > > if (!$result) { > > $error = true; > > } else { > > while ($row = pg_fetch_assoc($result)) { > > $pwd = $row["DIGEST_AUTH_PASSWORD"]; //hashed password > > $uid = $row["_URI"]; //uid used in other tables > > } > > } > > } > > > > if (!$error){ > > $A1 = $pwd; > > $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']); > > $valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2); > > if ($data['response'] != $valid_response){ > > $error = true; > > } > > } > > if (!$error){ > > return $uid; > > }else{ > > return false; > > } > > } > > > > > > > > On Wednesday, September 2, 2015 at 2:10:06 PM UTC-4, darub...@gmail.com wrote: > > > Can someone please share the PHP working code the accepts form substitutions and put them into my sql database... > > > > > > Thank you > > > > > > On Monday, June 8, 2015 at 7:55:30 PM UTC+3, gla...@gmail.com wrote: > > > > Hi, we've been trying to implement a PHP script which accepts requests from Collect and sends them to Aggregate. The reason why we are doing this is because we need to restrict which user can see which forms, something that isn't possible with Aggregate. So far, we've been able to implement the user login and the forms list through /formList. We are trying to implement form submission (/submission), but we are struggling with the PHP code. It appears that the API used to submit data is not really documented and doesn't appear to follow the OpenRosa standard described here: > > > > > > > > https://bitbucket.org/javarosa/javarosa/wiki/FormSubmissionAPI > > > > > > > > The code in Collect: > > > > > > > > https://code.google.com/p/opendatakit/source/browse/src/org/odk/collect/android/tasks/InstanceUploaderTask.java?repo=collect > > > > > > > > Seems to indicate that the communication between Collect and Aggregate relies on a 204 http response which is not mentioned in the OpenRosa standards. Also, it seems to also require a Location: in the header, which is contradictory with the "204 No Content" response. In PHP, issuing a Location in the header automatically converts the response into a 301 or 302 and ignores the 204. > > > > Hi ...has this worked for anyone? > > > > > > > Does anybody have a functioning PHP code sample to intercept data sent from Collect? > > > > > > > > I tried to use other PHP code samples posted in previous threads, but they appear to only issue a 204 reponse with no Location, which doesn't appear to work in recent versions of Collect. > > > > > > > > Thank you very much, > > > > > > > > Guillaume

And the Location redirection doesn't actually get exercised in ODK Collect
when connecting to ODK Aggregate, as the server is using the Spring
framework to handle scheme and authentication negotiations, so we never hit
our servlets until that is handled in the standard (30x) ways.

··· On Mon, Jun 8, 2015 at 3:33 PM, Mitch Sundt wrote:

Here's the history on why:

The 201/204 and the Location header were both attempts to detect Network
login screens. The Location header was the first attempt at this.

The current ODK Collect makes the Location header optional -- if supplied,
it can be used to redirect the submission path (/submission) to a different
path on the same server (or to a different scheme (e.g., https://); ODK
Collect does not allow a server to redirect to a different server URL.

ODK Aggregate always returns the .../submission URL as the Location, even
on a POST (and ODK Collect only processes the Location header on the HEAD
request). Returning this Location in response to a POST is not
expected/conformant REST behavior (it should return the download URL for
accessing the posted submission).

We then switched to the non-standard 201 return code to indicate a
successful interaction with the server and added the HEAD request to
confirm the scheme and authentication before the POST (so we never send
data over http unless the server accepts that, and we always have valid
authentication before sending large payloads to the server).

The question then became what to return from the initial HEAD request. We
can't determine the appropriate response from a HEAD request because the
response code is dependent upon the entity, and the HEAD request doesn't
contain one. So we settled on the 204 response, as the normal 201 response
does have an entity body which contains an XML response entity holding
information about the submission.

On Mon, Jun 8, 2015 at 12:51 PM, glaroc@gmail.com wrote:

Maybe I'm not understanding this correctly, but if the HEAD request
expects a Location back, shouldn't the response from the server be a 301
instead of a 204?

On Monday, June 8, 2015 at 3:37:25 PM UTC-4, Mitch wrote:

The 204 is expected to be returned in response to a HEAD request from
ODK Collect.

Every submission starts with a HEAD request followed by a POST.

This is done to (a) detect network login pages and (b) negotiate
authentication credentials prior to issuing the large POST of data when
submitting.

On Mon, Jun 8, 2015 at 10:42 AM, gla...@gmail.com wrote:
I've answered my own question shortly after posting this. It looks like
you can trick PHP into issuing 204 response while having a Location in the
header with this simple command:

header("Location: http://myserver.com/odk/",true,204);

I'm now able to intercept the posted files and send them to Agggregate.

Cheers,

Guillaume

On Monday, June 8, 2015 at 12:55:30 PM UTC-4, gla...@gmail.com wrote:

Hi, we've been trying to implement a PHP script which accepts
requests from Collect and sends them to Aggregate. The reason why we are
doing this is because we need to restrict which user can see which forms,
something that isn't possible with Aggregate. So far, we've been able to
implement the user login and the forms list through /formList. We are
trying to implement form submission (/submission), but we are struggling
with the PHP code. It appears that the API used to submit data is not
really documented and doesn't appear to follow the OpenRosa standard
described here:

https://bitbucket.org/javarosa/javarosa/wiki/FormSubmissionAPI

The code in Collect:

https://code.google.com/p/opendatakit/source/browse/src/org/odk/collect/android/tasks/InstanceUploaderTask.java?repo=collect

Seems to indicate that the communication between Collect and
Aggregate relies on a 204 http response which is not mentioned in the
OpenRosa standards. Also, it seems to also require a Location: in the
header, which is contradictory with the "204 No Content" response. In PHP,
issuing a Location in the header automatically converts the response into a
301 or 302 and ignores the 204.

Does anybody have a functioning PHP code sample to intercept data
sent from Collect?

I tried to use other PHP code samples posted in previous threads, but
they appear to only issue a 204 reponse with no Location, which doesn't
appear to work in recent versions of Collect.

Thank you very much,

Guillaume

--

You received this message because you are subscribed to the Google
Groups "ODK Developers" group.

To unsubscribe from this group and stop receiving emails from it, send
an email to opendatakit-developers+unsubscribe@googlegroups.com.

For more options, visit https://groups.google.com/d/optout.

--

Mitch Sundt
Software Engineer
University of Washington
mitche...@gmail.com

--
You received this message because you are subscribed to the Google Groups
"ODK Developers" group.
To unsubscribe from this group and stop receiving emails from it, send an
email to opendatakit-developers+unsubscribe@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

--
Mitch Sundt
Software Engineer
University of Washington
mitchellsundt@gmail.com

--
Mitch Sundt
Software Engineer
University of Washington
mitchellsundt@gmail.com

Thanks...
do I need only this code or you can share the whole php project.

··· On Wed, Feb 3, 2016 at 9:33 PM, wrote:

It works for us...

On Wednesday, February 3, 2016 at 1:24:35 PM UTC-5, krcsde...@gmail.com wrote:

On Wednesday, September 2, 2015 at 9:59:20 PM UTC+3, gla...@gmail.com wrote:

Here is code for a formList/index.php file that will intercept Collect
submissions, validate the login and password of the user, and only show
forms submitted by this user. Note that this is in PostgreSQL, not MySQL.

$error = false;
$elog = "";

if (empty($_SERVER['PHP_AUTH_DIGEST'])){ // before credentials

http_response_code(401);
header("HTTP/1.1 401 Unauthorized");
header('Content-Type: text/xml; charset=utf-8');
header('WWW-Authenticate: Digest realm="**INSERT YOUR REALM

HERE**",qop="auth",nonce="'.uniqid().'",opaque="'.md5('INSERT YOUR REALM
HERE
').'"');

header('"HTTP_X_OPENROSA_VERSION": "1.0"');
header('X-OpenRosa-Version:1.0');

} else { // after credentials

header('Content-Type: text/xml; charset=utf-8');
header('"HTTP_X_OPENROSA_VERSION": "1.0"');
header('X-OpenRosa-Version:1.0');

$uid=check_user_pass();
if ($uid!==false){
    echo '<xforms xmlns="http://openrosa.org/xforms/xformsList">';
    $uid = pg_escape_literal($uid);
    $query = 'SELECT * FROM odk_prod._form_info WHERE

"_CREATOR_URI_USER" = '.$uid.' AND "_IS_COMPLETE" = TRUE';

    $result = pg_query($con_pg, $query);
    if (!$result) {
        $error = true;
    } else {
        while ($row = pg_fetch_assoc($result)) {
            $form = $row["FORM_ID"];
            $query = 'SELECT "FORM_NAME",

"ROOT_ELEMENT_MODEL_VERSION" FROM odk_prod._form_info_fileset WHERE
"_TOP_LEVEL_AURI" = ''.$row['_URI'].''';

            $result_ref = pg_query($con_pg,$query);
            $row_ref=pg_fetch_assoc($result_ref);
            echo '<xform>';
            echo '<formID>'.$form.'</formID>';
            echo '<name>'.$row_ref['FORM_NAME'].'</name>';
            echo

''.$row_ref['ROOT_ELEMENT_MODEL_VERSION'].'';

            echo

''.$row_ref['ROOT_ELEMENT_MODEL_VERSION'].'';

            echo '<hash>'.$row['_URI'].'</hash>';
            echo '<downloadUrl>

http://quebio.ca/odk/formXML/?formId='.$form.'';

            $query = 'SELECT * FROM

odk_prod._form_info_manifest_bin WHERE "_TOP_LEVEL_AURI" =
''.$row['_URI'].''';

            $result2 = pg_query($con_pg, $query);
            if (pg_num_rows($result2)>0){
            echo '<manifestUrl>http://

YOUR_SERVER_ADDRESS/formList/xformsManifest.php?formId='.$form.'';

            }
            echo '</xform>';
        }
    }
    echo '</xforms>';
}

}

function check_user_pass() {
$data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST']);
$name = $data['username'];
$error=false;
// double check connection
if (!$con_pg) {
$error = true;
}

// query db for hashed password for given username
if (!$error){
    $name = pg_escape_literal($name);
    $query = 'SELECT * FROM odk_prod._registered_users WHERE

"LOCAL_USERNAME" = '.$name.' AND "IS_REMOVED" = FALSE';

    $result = pg_query($con_pg, $query);
    if (!$result) {
        $error = true;
    } else {
        while ($row = pg_fetch_assoc($result)) {
          $pwd = $row["DIGEST_AUTH_PASSWORD"]; //hashed password
          $uid = $row["_URI"]; //uid used in other tables
        }
    }
}

if (!$error){
    $A1 = $pwd;
    $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']);
    $valid_response =

md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2);

    if ($data['response'] != $valid_response){
        $error = true;
    }
}
if (!$error){
    return $uid;
}else{
    return false;
}

}

On Wednesday, September 2, 2015 at 2:10:06 PM UTC-4, darub...@gmail.com wrote:

Can someone please share the PHP working code the accepts form
substitutions and put them into my sql database...

Thank you

On Monday, June 8, 2015 at 7:55:30 PM UTC+3, gla...@gmail.com wrote:

Hi, we've been trying to implement a PHP script which accepts
requests from Collect and sends them to Aggregate. The reason why we are
doing this is because we need to restrict which user can see which forms,
something that isn't possible with Aggregate. So far, we've been able to
implement the user login and the forms list through /formList. We are
trying to implement form submission (/submission), but we are struggling
with the PHP code. It appears that the API used to submit data is not
really documented and doesn't appear to follow the OpenRosa standard
described here:

https://bitbucket.org/javarosa/javarosa/wiki/FormSubmissionAPI

The code in Collect:

https://code.google.com/p/opendatakit/source/browse/src/org/odk/collect/android/tasks/InstanceUploaderTask.java?repo=collect

Seems to indicate that the communication between Collect and
Aggregate relies on a 204 http response which is not mentioned in the
OpenRosa standards. Also, it seems to also require a Location: in the
header, which is contradictory with the "204 No Content" response. In PHP,
issuing a Location in the header automatically converts the response into a
301 or 302 and ignores the 204.
Hi ...has this worked for anyone?

Does anybody have a functioning PHP code sample to intercept data
sent from Collect?

I tried to use other PHP code samples posted in previous threads,
but they appear to only issue a 204 reponse with no Location, which doesn't
appear to work in recent versions of Collect.

Thank you very much,

Guillaume

Thank you for your detailed response.

When you say;

"The current ODK Collect makes the Location header optional -- if supplied, it can be used to redirect the submission path (/submission) to a different path on the same server (or to a different scheme (e.g., https://);"

I was lead to think otherwise when seeing the piece of code that handles the response:

https://code.google.com/p/opendatakit/source/browse/src/org/odk/collect/android/tasks/InstanceUploaderTask.java?repo=collect#146

           } else if (statusCode == 204) {
                    Header[] locations = response.getHeaders("Location");
                    WebUtils.discardEntityBytes(response);
                if (locations != null && locations.length == 1) {

Anyway, I've sorted out a way to handle this with PHP.

Thanks again for your time and response.

Guillaume

··· On Monday, June 8, 2015 at 6:49:21 PM UTC-4, Mitch wrote: > And the Location redirection doesn't actually get exercised in ODK Collect when connecting to ODK Aggregate, as the server is using the Spring framework to handle scheme and authentication negotiations, so we never hit our servlets until that is handled in the standard (30x) ways. > > > > > On Mon, Jun 8, 2015 at 3:33 PM, Mitch Sundt wrote: > > Here's the history on why: > > The 201/204 and the Location header were both attempts to detect Network login screens. The Location header was the first attempt at this. > > > The current ODK Collect makes the Location header optional -- if supplied, it can be used to redirect the submission path (/submission) to a different path on the same server (or to a different scheme (e.g., https://); ODK Collect does not allow a server to redirect to a different server URL. > > > ODK Aggregate always returns the .../submission URL as the Location, even on a POST (and ODK Collect only processes the Location header on the HEAD request). Returning this Location in response to a POST is not expected/conformant REST behavior (it should return the download URL for accessing the posted submission). > > > > We then switched to the non-standard 201 return code to indicate a successful interaction with the server and added the HEAD request to confirm the scheme and authentication before the POST (so we never send data over http unless the server accepts that, and we always have valid authentication before sending large payloads to the server). > > The question then became what to return from the initial HEAD request. We can't determine the appropriate response from a HEAD request because the response code is dependent upon the entity, and the HEAD request doesn't contain one. So we settled on the 204 response, as the normal 201 response does have an entity body which contains an XML response entity holding information about the submission. > > > > > > > > On Mon, Jun 8, 2015 at 12:51 PM, wrote: > Maybe I'm not understanding this correctly, but if the HEAD request expects a Location back, shouldn't the response from the server be a 301 instead of a 204? > > > > > > > > On Monday, June 8, 2015 at 3:37:25 PM UTC-4, Mitch wrote: > > > The 204 is expected to be returned in response to a HEAD request from ODK Collect. > > > > > > Every submission starts with a HEAD request followed by a POST. > > > > > > > > > This is done to (a) detect network login pages and (b) negotiate authentication credentials prior to issuing the large POST of data when submitting. > > > > > > > > > > > > > > > On Mon, Jun 8, 2015 at 10:42 AM, wrote: > > > I've answered my own question shortly after posting this. It looks like you can trick PHP into issuing 204 response while having a Location in the header with this simple command: > > > > > > > > > > > > header("Location: http://myserver.com/odk/",true,204); > > > > > > > > > > > > I'm now able to intercept the posted files and send them to Agggregate. > > > > > > > > > > > > Cheers, > > > > > > > > > > > > Guillaume > > > > > > > > > > > > > > > > > > On Monday, June 8, 2015 at 12:55:30 PM UTC-4, gla...@gmail.com wrote: > > > > > > > Hi, we've been trying to implement a PHP script which accepts requests from Collect and sends them to Aggregate. The reason why we are doing this is because we need to restrict which user can see which forms, something that isn't possible with Aggregate. So far, we've been able to implement the user login and the forms list through /formList. We are trying to implement form submission (/submission), but we are struggling with the PHP code. It appears that the API used to submit data is not really documented and doesn't appear to follow the OpenRosa standard described here: > > > > > > > > > > > > > > https://bitbucket.org/javarosa/javarosa/wiki/FormSubmissionAPI > > > > > > > > > > > > > > The code in Collect: > > > > > > > > > > > > > > https://code.google.com/p/opendatakit/source/browse/src/org/odk/collect/android/tasks/InstanceUploaderTask.java?repo=collect > > > > > > > > > > > > > > Seems to indicate that the communication between Collect and Aggregate relies on a 204 http response which is not mentioned in the OpenRosa standards. Also, it seems to also require a Location: in the header, which is contradictory with the "204 No Content" response. In PHP, issuing a Location in the header automatically converts the response into a 301 or 302 and ignores the 204. > > > > > > > > > > > > > > Does anybody have a functioning PHP code sample to intercept data sent from Collect? > > > > > > > > > > > > > > I tried to use other PHP code samples posted in previous threads, but they appear to only issue a 204 reponse with no Location, which doesn't appear to work in recent versions of Collect. > > > > > > > > > > > > > > Thank you very much, > > > > > > > > > > > > > > Guillaume > > > > > > > > > > > > -- > > > > > > You received this message because you are subscribed to the Google Groups "ODK Developers" group. > > > > > > To unsubscribe from this group and stop receiving emails from it, send an email to opendatakit-developers+unsubscribe@googlegroups.com. > > > > > > For more options, visit https://groups.google.com/d/optout. > > > > > > > > > > > > > > > -- > > > > > > Mitch Sundt > > > Software Engineer > > > University of Washington > > > mitche...@gmail.com > > > > > > -- > > You received this message because you are subscribed to the Google Groups "ODK Developers" group. > > To unsubscribe from this group and stop receiving emails from it, send an email to opendatakit-developers+unsubscribe@googlegroups.com. > > For more options, visit https://groups.google.com/d/optout. > > > > > -- > > > > Mitch Sundt > Software Engineer > University of Washington > mitche...@gmail.com > > > > > -- > > Mitch Sundt > Software Engineer > University of Washington > mitche...@gmail.com

You can check this blog post, it should give you a good start.

http://guillaume.larocque.space/2016/Intercept-odk-collect-submissions/

Guillaume

··· On Monday, February 8, 2016 at 5:14:23 AM UTC-5, Darubini Head Quarters wrote: > Thanks... > do I need only this code or you can share the whole php project. > > > On Wed, Feb 3, 2016 at 9:33 PM, wrote: > It works for us... > > > > > > On Wednesday, February 3, 2016 at 1:24:35 PM UTC-5, krcsde...@gmail.com wrote: > > > On Wednesday, September 2, 2015 at 9:59:20 PM UTC+3, gla...@gmail.com wrote: > > > > Here is code for a formList/index.php file that will intercept Collect submissions, validate the login and password of the user, and only show forms submitted by this user. Note that this is in PostgreSQL, not MySQL. > > > > > > > > $error = false; > > > > $elog = ""; > > > > > > > > if (empty($_SERVER['PHP_AUTH_DIGEST'])){ // before credentials > > > > > > > > http_response_code(401); > > > > header("HTTP/1.1 401 Unauthorized"); > > > > header('Content-Type: text/xml; charset=utf-8'); > > > > header('WWW-Authenticate: Digest realm="**INSERT YOUR REALM HERE**",qop="auth",nonce="'.uniqid().'",opaque="'.md5('**INSERT YOUR REALM HERE**').'"'); > > > > header('"HTTP_X_OPENROSA_VERSION": "1.0"'); > > > > header('X-OpenRosa-Version:1.0'); > > > > > > > > } else { // after credentials > > > > > > > > header('Content-Type: text/xml; charset=utf-8'); > > > > header('"HTTP_X_OPENROSA_VERSION": "1.0"'); > > > > header('X-OpenRosa-Version:1.0'); > > > > > > > > $uid=check_user_pass(); > > > > if ($uid!==false){ > > > > echo ''; > > > > $uid = pg_escape_literal($uid); > > > > $query = 'SELECT * FROM odk_prod._form_info WHERE "_CREATOR_URI_USER" = '.$uid.' AND "_IS_COMPLETE" = TRUE'; > > > > $result = pg_query($con_pg, $query); > > > > if (!$result) { > > > > $error = true; > > > > } else { > > > > while ($row = pg_fetch_assoc($result)) { > > > > $form = $row["FORM_ID"]; > > > > $query = 'SELECT "FORM_NAME", "ROOT_ELEMENT_MODEL_VERSION" FROM odk_prod._form_info_fileset WHERE "_TOP_LEVEL_AURI" = \''.$row['_URI'].'\''; > > > > $result_ref = pg_query($con_pg,$query); > > > > $row_ref=pg_fetch_assoc($result_ref); > > > > echo ''; > > > > echo ''.$form.''; > > > > echo ''.$row_ref['FORM_NAME'].''; > > > > echo ''.$row_ref['ROOT_ELEMENT_MODEL_VERSION'].''; > > > > echo ''.$row_ref['ROOT_ELEMENT_MODEL_VERSION'].''; > > > > echo ''.$row['_URI'].''; > > > > echo 'http://quebio.ca/odk/formXML/?formId='.$form.''; > > > > $query = 'SELECT * FROM odk_prod._form_info_manifest_bin WHERE "_TOP_LEVEL_AURI" = \''.$row['_URI'].'\''; > > > > $result2 = pg_query($con_pg, $query); > > > > if (pg_num_rows($result2)>0){ > > > > echo 'http://**YOUR_SERVER_ADDRESS**/formList/xformsManifest.php?formId='.$form.''; > > > > } > > > > echo ''; > > > > } > > > > } > > > > echo ''; > > > > } > > > > } > > > > > > > > > > > > function check_user_pass() { > > > > $data = http_digest_parse($_SERVER['PHP_AUTH_DIGEST']); > > > > $name = $data['username']; > > > > $error=false; > > > > // double check connection > > > > if (!$con_pg) { > > > > $error = true; > > > > } > > > > > > > > // query db for hashed password for given username > > > > if (!$error){ > > > > $name = pg_escape_literal($name); > > > > $query = 'SELECT * FROM odk_prod._registered_users WHERE "LOCAL_USERNAME" = '.$name.' AND "IS_REMOVED" = FALSE'; > > > > $result = pg_query($con_pg, $query); > > > > if (!$result) { > > > > $error = true; > > > > } else { > > > > while ($row = pg_fetch_assoc($result)) { > > > > $pwd = $row["DIGEST_AUTH_PASSWORD"]; //hashed password > > > > $uid = $row["_URI"]; //uid used in other tables > > > > } > > > > } > > > > } > > > > > > > > if (!$error){ > > > > $A1 = $pwd; > > > > $A2 = md5($_SERVER['REQUEST_METHOD'].':'.$data['uri']); > > > > $valid_response = md5($A1.':'.$data['nonce'].':'.$data['nc'].':'.$data['cnonce'].':'.$data['qop'].':'.$A2); > > > > if ($data['response'] != $valid_response){ > > > > $error = true; > > > > } > > > > } > > > > if (!$error){ > > > > return $uid; > > > > }else{ > > > > return false; > > > > } > > > > } > > > > > > > > > > > > > > > > On Wednesday, September 2, 2015 at 2:10:06 PM UTC-4, darub...@gmail.com wrote: > > > > > Can someone please share the PHP working code the accepts form substitutions and put them into my sql database... > > > > > > > > > > Thank you > > > > > > > > > > On Monday, June 8, 2015 at 7:55:30 PM UTC+3, gla...@gmail.com wrote: > > > > > > Hi, we've been trying to implement a PHP script which accepts requests from Collect and sends them to Aggregate. The reason why we are doing this is because we need to restrict which user can see which forms, something that isn't possible with Aggregate. So far, we've been able to implement the user login and the forms list through /formList. We are trying to implement form submission (/submission), but we are struggling with the PHP code. It appears that the API used to submit data is not really documented and doesn't appear to follow the OpenRosa standard described here: > > > > > > > > > > > > https://bitbucket.org/javarosa/javarosa/wiki/FormSubmissionAPI > > > > > > > > > > > > The code in Collect: > > > > > > > > > > > > https://code.google.com/p/opendatakit/source/browse/src/org/odk/collect/android/tasks/InstanceUploaderTask.java?repo=collect > > > > > > > > > > > > Seems to indicate that the communication between Collect and Aggregate relies on a 204 http response which is not mentioned in the OpenRosa standards. Also, it seems to also require a Location: in the header, which is contradictory with the "204 No Content" response. In PHP, issuing a Location in the header automatically converts the response into a 301 or 302 and ignores the 204. > > > > > > Hi ...has this worked for anyone? > > > > > > > > > > > > > > > Does anybody have a functioning PHP code sample to intercept data sent from Collect? > > > > > > > > > > > > I tried to use other PHP code samples posted in previous threads, but they appear to only issue a 204 reponse with no Location, which doesn't appear to work in recent versions of Collect. > > > > > > > > > > > > Thank you very much, > > > > > > > > > > > > Guillaume