1 2 Previous Next 23 Replies Latest reply on Feb 7, 2017 2:40 PM by mdurie

    getContainerDataURL Causes HTTP 401 Error

    jsorge

      Hey all,

      I'm using an externally stored container in my data file, and my PHP code is calling the getContainerDataURL method to return a URL to the container file. However, when I click on the link it pops up a login box, and if I click cancel then it gives me an HTTP 401 error and that the operation needs HTTP authentication to proceed. I know that everything should be hooked up properly because I'm getting data from other places in the system without issue. Here's a snippet of my code so you can see what I'm doing:

      <a href="<?php echo $fm -> getContainerDataURL ( $invoices_record -> getField('File') ); ?>"><?php echo $invoices_record->getField('Description'); ?>

       

      Is there something here that looks off? Or is this something that's a known issue with some sort of workaround? The problem this is presenting is we use this technique to allow customers to download their invoices from our website and it's broken. Thanks for any help.

      jared

        • 1. Re: getContainerDataURL Causes HTTP 401 Error
          TimDietrich

          Jared --

           

          I've run into this before.

           

          This is going to sound lame, but the first thing I would do is make absolutely sure that you've got FileMaker Server fully updated. That alone might solve the problem...

           

          "Might" being the operative word, of course!

           

          -- Tim

          • 2. Re: getContainerDataURL Causes HTTP 401 Error
            jsorge

            Hi Tim,

            I do have the server up to date. We are running 12.0.4.405 on Mac OS X 10.8.4. What did you do to resolve the issue?

             

            I've also openend this up as an issue report here: http://forums.filemaker.com/posts/fed86a045c.

             

            Thanks!

            jared

            • 3. Re: getContainerDataURL Causes HTTP 401 Error
              TimDietrich

              Jared --

               

              Here's another possible solution for you...

               

              From what I've been able to tell, the issue is this: While you are authenticated when you use the API to get the URL (via the "getContainerDataURL" method), the URL itself doesn't include credentials that allow Tomcat to authenticate the request it receives when the URL is actually used. So when you pass the URL to the Web app's user, the request that they generate cannot be authenticated. That's why the 401 error is being thrown.

               

              Here's what I ended up having to do...

               

              1. Get the URL to the container data, using getContainerDataURL (just as you are now).

               

              2. Instead of directly referencing that URL, use it in a link that passes it to another PHP file that acts as a proxy. The link to that file might look like this: <a href="external_container.php?container_url=$getContainerDataURL">Some Link</a>. (You might need to urlencode the $getContainerDataURL value.)

               

              3. The "external_container.php" file looks something like this...

               

               

              // Get the app settings.

              // This file sets the values for FM_USERNAME and FM_PASSWORD, which are used below.

              require_once ( 'settings_init.php' );

               

              // Build the URL, and add the FM credentials.

              $url =  'http://' . FM_USERNAME . ':' . FM_PASSWORD . '@' . $_GET['container_url'];

               

              // Use cURL to get the binary data.

              $ch = curl_init();

              curl_setopt( $ch, CURLOPT_URL, $url );

              curl_setopt( $ch, CURLOPT_USERAGENT, 'FM API Container Handler/1.0' );

              curl_setopt( $ch, CURLOPT_RETURNTRANSFER, TRUE );

              curl_setopt( $ch, CURLOPT_TIMEOUT, 30 );

              $container_data = curl_exec( $ch );

               

              // Echo back the binary data.

              header( 'Content-Length: ' . strlen( $container_data ) );

              header( 'Cache-Control: private' );

              echo $container_data;

               

               

              My version is a little more complicated, because of the various types of files that are being stored in the container. So there is additional code that looks at the type of file in the container, and then sets the Content-Type and Content-Disposition accordingly. (Hopefully you won't need all of that - but if you do, let me know.)

               

              I hope this helps.

               

              -- Tim

              • 4. Re: getContainerDataURL Causes HTTP 401 Error
                jsorge

                I'm getting a white screen when I implement this script. I'm setting up the url correctly but when the curl_exec command is run it returns 0. I've setup everything like you have here. Any ideas? I've not used the curl function before so I'm still figuring everything out. Thanks for your responses.

                jared

                • 5. Re: getContainerDataURL Causes HTTP 401 Error
                  TimDietrich

                  Jared --

                   

                  Would you post the PHP script so that I can take a look at it?

                   

                  -- Tim

                  • 6. Re: getContainerDataURL Causes HTTP 401 Error
                    jsorge

                    I'm putting the script in a common directory, so that's why I need the boilerplate at the top.

                     

                    <?php

                    //Path to main site directory, used so the navigation menu knows where to navigate to

                    $siteDirectoryPath = "../";

                    //Path to common elements, used for menu code and menu graphics

                    $commonPath = $siteDirectoryPath."_common/";

                     

                     

                    require_once($siteDirectoryPath.'Connections/microstore.php');

                     

                     

                    $url = 'http://<USERNAME>:<PASSWORD>@' . $_GET['container_url'];

                     

                     

                    $ch = curl_init( $url );

                    /* curl_setopt( $ch, CURLOPT_URL, $url ); */

                    curl_setopt( $ch, CURLOPT_USERAGENT, 'FM API Container Handler/1.0' );

                    curl_setopt( $ch, CURLOPT_RETURNTRANSFER, TRUE );

                    curl_setopt( $ch, CURLOPT_TIMEOUT, 30 );

                    $container_data = curl_exec( $ch );

                    curl_close($ch);

                     

                     

                    if (!empty($container_data)) {

                        header('Content-Length: ' . strlen($container_data));

                        header('Cache-Control: private');

                        echo($container_data);

                    } else {

                        echo('Curl failed');

                    }

                     

                     

                    ?>

                    • 7. Re: getContainerDataURL Causes HTTP 401 Error
                      TimDietrich

                      Let's try this to see if you're at least getting something back from cURL...

                       

                      <?php

                      //Path to main site directory, used so the navigation menu knows where to navigate to

                      $siteDirectoryPath = "../";

                      //Path to common elements, used for menu code and menu graphics

                      $commonPath = $siteDirectoryPath."_common/";

                       

                      require_once($siteDirectoryPath.'Connections/microstore.php');

                       

                      $url = 'http://<USERNAME>:<PASSWORD>@' . $_GET['container_url'];

                       

                      $ch = curl_init( $url );

                      curl_setopt( $ch, CURLOPT_URL, $url );

                      curl_setopt( $ch, CURLOPT_USERAGENT, 'FM API Container Handler/1.0' );

                      curl_setopt( $ch, CURLOPT_RETURNTRANSFER, TRUE );

                      curl_setopt( $ch, CURLOPT_TIMEOUT, 30 );

                      $container_data = curl_exec( $ch );

                      curl_close($ch);

                       

                      if (!empty($container_data)) {

                                echo 'Length: ' . strlen($container_data);

                          // header('Content-Length: ' . strlen($container_data));

                          // header('Cache-Control: private');

                          // echo($container_data);

                      } else {

                          echo('Curl failed');

                      }

                       

                      ?>

                      • 8. Re: getContainerDataURL Causes HTTP 401 Error
                        jsorge

                        The cURL is still failing, returning a 0 on the curl_exec call.

                        • 9. Re: getContainerDataURL Causes HTTP 401 Error
                          TimDietrich

                          Ok, just for the fun of it, try setting the $url variable to something like 'http://www.filemaker.com' and see what you get.

                          • 10. Re: getContainerDataURL Causes HTTP 401 Error
                            jsorge

                            That works. It returns the proper length.

                            • 11. Re: getContainerDataURL Causes HTTP 401 Error
                              jsorge

                              I got it echoing binary data if I change the authentication to a curl_setopt option using CURLOPT_USERPWD, now I just need to have it interpret as a PDF (or jpg or whatever type it is).

                              • 12. Re: getContainerDataURL Causes HTTP 401 Error
                                TimDietrich

                                That's good news, because cURL is apparently installed.

                                 

                                Now, let's go back to your original code and see what happens if you do this...

                                 

                                <?php

                                //Path to main site directory, used so the navigation menu knows where to navigate to

                                $siteDirectoryPath = "../";

                                //Path to common elements, used for menu code and menu graphics

                                $commonPath = $siteDirectoryPath."_common/";

                                 

                                require_once($siteDirectoryPath.'Connections/microstore.php');

                                 

                                $url = 'http://<USERNAME>:<PASSWORD>@' . $_GET['container_url'];

                                 

                                die ( $url );

                                 

                                $ch = curl_init( $url );

                                curl_setopt( $ch, CURLOPT_URL, $url );

                                curl_setopt( $ch, CURLOPT_USERAGENT, 'FM API Container Handler/1.0' );

                                curl_setopt( $ch, CURLOPT_RETURNTRANSFER, TRUE );

                                curl_setopt( $ch, CURLOPT_TIMEOUT, 30 );

                                $container_data = curl_exec( $ch );

                                curl_close($ch);

                                 

                                if (!empty($container_data)) {

                                          echo 'Length: ' . strlen($container_data);

                                    // header('Content-Length: ' . strlen($container_data));

                                    // header('Cache-Control: private');

                                    // echo($container_data);

                                } else {

                                    echo('Curl failed');

                                }

                                 

                                ?>

                                 

                                 

                                That should echo out the value of $url and die. When it does, take the URL, copy and paste it into your browser, and see what you get.

                                 

                                You should get the container contents...

                                 

                                -- Tim

                                • 13. Re: getContainerDataURL Causes HTTP 401 Error
                                  TimDietrich

                                  Interesting! I've never had to use CURLOPT_USERPWD before.

                                   

                                  I think you just need to add this header and you'll get the PDFs to be handled properly: header( 'Content-type: application/pdf');

                                   

                                  Congrats on the progress. I remember how frustrating this was when I first ran into it.

                                   

                                  -- Tim

                                  • 14. Re: getContainerDataURL Causes HTTP 401 Error
                                    jsorge

                                    That did the trick. I'll have to create something to figure out what the Content-type is for the different formats, but for the most part we're dealing with PDF files so it's not a huge rush.

                                     

                                    Thanks so much for your help!

                                    jared

                                    1 2 Previous Next