Laravel 5.7 : 404 or 403 on storage/app/private whereas it works on storage/app/public












0















I am struggling to offer the user a link to a file that they can download when logged in. I read this and that (because eventually I want to protect the file from public access).



So under my app /storage folder I created a "private" directory next to "public". Inside it there is a subfolder "A" containing a "fileA.tar.gz" (I also tried with a simple test.txt without luck).



MyLaravelApp/
├── storage/
│ ├── public/
│ ├── private/
│ └── A/
│ └──fileA.tar.gz


In my controller I do :



$softwarePath = "private/A/fileA.tar.gz";

$urlToArchive = Storage::disk('local')->url(
$softwarePath);

$exists = Storage::disk('local')->exists($softwarePath); // returns true


But in the view when I click on the link http://127.0.0.1:8000/storage/private/A/fileA.tar.gz I get 404 although the exists function returns true.



So I tried to define in /config/filesystems.php a direct "short-cut" to my "private" folder :



'private' => [
'driver' => 'local',
'root' => storage_path('app/private'),
'url' => env('APP_URL').'/privateDownload',
'visibility' => 'public',
],


and made the following changes in the controller :



$softwarePath = "A/fileA.tar.gz";

$urlToArchive = Storage::disk('private')->url($softwarePath);

$exists = Storage::disk('private')->exists($softwarePath); // keeps returning true


But now I get 403 when I click on the generated link http://localhost/privateDownload/A/fileA.tar.gz (note the localhost without port address) and if I change the address to localhost:8000 I get the 404 back.



The route to the aforementioned controller is :



Route::get('/account', 'AccountController@showAccountDetails')->middleware('auth');


And I also tried to remove the middleware('auth') and access to private/A/fileA.tar.gz without luck (404).



Please note : if I keep the same subdirectory hierachy and moved it under public like :



MyLaravelApp/
├── storage/
│ ├── public/
│ └── A/
│ └──fileA.tar.gz
│ ├── private/


There is no issue, and the file can be downloaded. This is not interesting because I want to prevent this file from being downloaded without being logged in.



According to the doc and other SO answers it seems possible to access to a different directory than public. How can it be done ? Why exists() returns true whereas I get 404 then ? What's my setup / code failure actually?



Any help appreciated!



Solution



Based on @Namoshek's answer, here is what I did (for the records) :



In the aforementioned controller I simply checked whether or not the user has the right to download fileA. If so then I return a view which has a link to a route named downloadFileA that points to a function downloadFileA still in the same aforementioned controller.



Finally in the function downloadFileA I return Storage::disk('private')->download('fileA') after checking whether the user is entitled or not to download the file. So I check twice but that's not a problem because there is very low traffic (once a week or so).










share|improve this question





























    0















    I am struggling to offer the user a link to a file that they can download when logged in. I read this and that (because eventually I want to protect the file from public access).



    So under my app /storage folder I created a "private" directory next to "public". Inside it there is a subfolder "A" containing a "fileA.tar.gz" (I also tried with a simple test.txt without luck).



    MyLaravelApp/
    ├── storage/
    │ ├── public/
    │ ├── private/
    │ └── A/
    │ └──fileA.tar.gz


    In my controller I do :



    $softwarePath = "private/A/fileA.tar.gz";

    $urlToArchive = Storage::disk('local')->url(
    $softwarePath);

    $exists = Storage::disk('local')->exists($softwarePath); // returns true


    But in the view when I click on the link http://127.0.0.1:8000/storage/private/A/fileA.tar.gz I get 404 although the exists function returns true.



    So I tried to define in /config/filesystems.php a direct "short-cut" to my "private" folder :



    'private' => [
    'driver' => 'local',
    'root' => storage_path('app/private'),
    'url' => env('APP_URL').'/privateDownload',
    'visibility' => 'public',
    ],


    and made the following changes in the controller :



    $softwarePath = "A/fileA.tar.gz";

    $urlToArchive = Storage::disk('private')->url($softwarePath);

    $exists = Storage::disk('private')->exists($softwarePath); // keeps returning true


    But now I get 403 when I click on the generated link http://localhost/privateDownload/A/fileA.tar.gz (note the localhost without port address) and if I change the address to localhost:8000 I get the 404 back.



    The route to the aforementioned controller is :



    Route::get('/account', 'AccountController@showAccountDetails')->middleware('auth');


    And I also tried to remove the middleware('auth') and access to private/A/fileA.tar.gz without luck (404).



    Please note : if I keep the same subdirectory hierachy and moved it under public like :



    MyLaravelApp/
    ├── storage/
    │ ├── public/
    │ └── A/
    │ └──fileA.tar.gz
    │ ├── private/


    There is no issue, and the file can be downloaded. This is not interesting because I want to prevent this file from being downloaded without being logged in.



    According to the doc and other SO answers it seems possible to access to a different directory than public. How can it be done ? Why exists() returns true whereas I get 404 then ? What's my setup / code failure actually?



    Any help appreciated!



    Solution



    Based on @Namoshek's answer, here is what I did (for the records) :



    In the aforementioned controller I simply checked whether or not the user has the right to download fileA. If so then I return a view which has a link to a route named downloadFileA that points to a function downloadFileA still in the same aforementioned controller.



    Finally in the function downloadFileA I return Storage::disk('private')->download('fileA') after checking whether the user is entitled or not to download the file. So I check twice but that's not a problem because there is very low traffic (once a week or so).










    share|improve this question



























      0












      0








      0








      I am struggling to offer the user a link to a file that they can download when logged in. I read this and that (because eventually I want to protect the file from public access).



      So under my app /storage folder I created a "private" directory next to "public". Inside it there is a subfolder "A" containing a "fileA.tar.gz" (I also tried with a simple test.txt without luck).



      MyLaravelApp/
      ├── storage/
      │ ├── public/
      │ ├── private/
      │ └── A/
      │ └──fileA.tar.gz


      In my controller I do :



      $softwarePath = "private/A/fileA.tar.gz";

      $urlToArchive = Storage::disk('local')->url(
      $softwarePath);

      $exists = Storage::disk('local')->exists($softwarePath); // returns true


      But in the view when I click on the link http://127.0.0.1:8000/storage/private/A/fileA.tar.gz I get 404 although the exists function returns true.



      So I tried to define in /config/filesystems.php a direct "short-cut" to my "private" folder :



      'private' => [
      'driver' => 'local',
      'root' => storage_path('app/private'),
      'url' => env('APP_URL').'/privateDownload',
      'visibility' => 'public',
      ],


      and made the following changes in the controller :



      $softwarePath = "A/fileA.tar.gz";

      $urlToArchive = Storage::disk('private')->url($softwarePath);

      $exists = Storage::disk('private')->exists($softwarePath); // keeps returning true


      But now I get 403 when I click on the generated link http://localhost/privateDownload/A/fileA.tar.gz (note the localhost without port address) and if I change the address to localhost:8000 I get the 404 back.



      The route to the aforementioned controller is :



      Route::get('/account', 'AccountController@showAccountDetails')->middleware('auth');


      And I also tried to remove the middleware('auth') and access to private/A/fileA.tar.gz without luck (404).



      Please note : if I keep the same subdirectory hierachy and moved it under public like :



      MyLaravelApp/
      ├── storage/
      │ ├── public/
      │ └── A/
      │ └──fileA.tar.gz
      │ ├── private/


      There is no issue, and the file can be downloaded. This is not interesting because I want to prevent this file from being downloaded without being logged in.



      According to the doc and other SO answers it seems possible to access to a different directory than public. How can it be done ? Why exists() returns true whereas I get 404 then ? What's my setup / code failure actually?



      Any help appreciated!



      Solution



      Based on @Namoshek's answer, here is what I did (for the records) :



      In the aforementioned controller I simply checked whether or not the user has the right to download fileA. If so then I return a view which has a link to a route named downloadFileA that points to a function downloadFileA still in the same aforementioned controller.



      Finally in the function downloadFileA I return Storage::disk('private')->download('fileA') after checking whether the user is entitled or not to download the file. So I check twice but that's not a problem because there is very low traffic (once a week or so).










      share|improve this question
















      I am struggling to offer the user a link to a file that they can download when logged in. I read this and that (because eventually I want to protect the file from public access).



      So under my app /storage folder I created a "private" directory next to "public". Inside it there is a subfolder "A" containing a "fileA.tar.gz" (I also tried with a simple test.txt without luck).



      MyLaravelApp/
      ├── storage/
      │ ├── public/
      │ ├── private/
      │ └── A/
      │ └──fileA.tar.gz


      In my controller I do :



      $softwarePath = "private/A/fileA.tar.gz";

      $urlToArchive = Storage::disk('local')->url(
      $softwarePath);

      $exists = Storage::disk('local')->exists($softwarePath); // returns true


      But in the view when I click on the link http://127.0.0.1:8000/storage/private/A/fileA.tar.gz I get 404 although the exists function returns true.



      So I tried to define in /config/filesystems.php a direct "short-cut" to my "private" folder :



      'private' => [
      'driver' => 'local',
      'root' => storage_path('app/private'),
      'url' => env('APP_URL').'/privateDownload',
      'visibility' => 'public',
      ],


      and made the following changes in the controller :



      $softwarePath = "A/fileA.tar.gz";

      $urlToArchive = Storage::disk('private')->url($softwarePath);

      $exists = Storage::disk('private')->exists($softwarePath); // keeps returning true


      But now I get 403 when I click on the generated link http://localhost/privateDownload/A/fileA.tar.gz (note the localhost without port address) and if I change the address to localhost:8000 I get the 404 back.



      The route to the aforementioned controller is :



      Route::get('/account', 'AccountController@showAccountDetails')->middleware('auth');


      And I also tried to remove the middleware('auth') and access to private/A/fileA.tar.gz without luck (404).



      Please note : if I keep the same subdirectory hierachy and moved it under public like :



      MyLaravelApp/
      ├── storage/
      │ ├── public/
      │ └── A/
      │ └──fileA.tar.gz
      │ ├── private/


      There is no issue, and the file can be downloaded. This is not interesting because I want to prevent this file from being downloaded without being logged in.



      According to the doc and other SO answers it seems possible to access to a different directory than public. How can it be done ? Why exists() returns true whereas I get 404 then ? What's my setup / code failure actually?



      Any help appreciated!



      Solution



      Based on @Namoshek's answer, here is what I did (for the records) :



      In the aforementioned controller I simply checked whether or not the user has the right to download fileA. If so then I return a view which has a link to a route named downloadFileA that points to a function downloadFileA still in the same aforementioned controller.



      Finally in the function downloadFileA I return Storage::disk('private')->download('fileA') after checking whether the user is entitled or not to download the file. So I check twice but that's not a problem because there is very low traffic (once a week or so).







      laravel laravel-5 laravel-5.7






      share|improve this question















      share|improve this question













      share|improve this question




      share|improve this question








      edited Nov 23 '18 at 11:00







      HelloWorld

















      asked Nov 22 '18 at 2:23









      HelloWorldHelloWorld

      1,005612




      1,005612
























          1 Answer
          1






          active

          oldest

          votes


















          1














          You can use Storage::download('filename.xyz') instead of generating a URL with Storage::url('filename.xyu'). This will send the file as content of the response. It may be resource intensive for large files though.






          share|improve this answer
























          • Thanks @Namoshek! I updated my question with the solution I used based on your answer.

            – HelloWorld
            Nov 23 '18 at 10:51













          • Note about your comment in the solution So I check twice but that's not a problem because there is very low traffic (once a week or so): It is actually required for you to check the permissions twice (at least from what I got from the requirements). Otherwise a user with the permission to see or download the file could simply send the link to someone else. And to be fair, such a permission check does not cost a lot of resources at all.

            – Namoshek
            Nov 23 '18 at 11:08











          Your Answer






          StackExchange.ifUsing("editor", function () {
          StackExchange.using("externalEditor", function () {
          StackExchange.using("snippets", function () {
          StackExchange.snippets.init();
          });
          });
          }, "code-snippets");

          StackExchange.ready(function() {
          var channelOptions = {
          tags: "".split(" "),
          id: "1"
          };
          initTagRenderer("".split(" "), "".split(" "), channelOptions);

          StackExchange.using("externalEditor", function() {
          // Have to fire editor after snippets, if snippets enabled
          if (StackExchange.settings.snippets.snippetsEnabled) {
          StackExchange.using("snippets", function() {
          createEditor();
          });
          }
          else {
          createEditor();
          }
          });

          function createEditor() {
          StackExchange.prepareEditor({
          heartbeatType: 'answer',
          autoActivateHeartbeat: false,
          convertImagesToLinks: true,
          noModals: true,
          showLowRepImageUploadWarning: true,
          reputationToPostImages: 10,
          bindNavPrevention: true,
          postfix: "",
          imageUploader: {
          brandingHtml: "Powered by u003ca class="icon-imgur-white" href="https://imgur.com/"u003eu003c/au003e",
          contentPolicyHtml: "User contributions licensed under u003ca href="https://creativecommons.org/licenses/by-sa/3.0/"u003ecc by-sa 3.0 with attribution requiredu003c/au003e u003ca href="https://stackoverflow.com/legal/content-policy"u003e(content policy)u003c/au003e",
          allowUrls: true
          },
          onDemand: true,
          discardSelector: ".discard-answer"
          ,immediatelyShowMarkdownHelp:true
          });


          }
          });














          draft saved

          draft discarded


















          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53423032%2flaravel-5-7-404-or-403-on-storage-app-private-whereas-it-works-on-storage-app%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown

























          1 Answer
          1






          active

          oldest

          votes








          1 Answer
          1






          active

          oldest

          votes









          active

          oldest

          votes






          active

          oldest

          votes









          1














          You can use Storage::download('filename.xyz') instead of generating a URL with Storage::url('filename.xyu'). This will send the file as content of the response. It may be resource intensive for large files though.






          share|improve this answer
























          • Thanks @Namoshek! I updated my question with the solution I used based on your answer.

            – HelloWorld
            Nov 23 '18 at 10:51













          • Note about your comment in the solution So I check twice but that's not a problem because there is very low traffic (once a week or so): It is actually required for you to check the permissions twice (at least from what I got from the requirements). Otherwise a user with the permission to see or download the file could simply send the link to someone else. And to be fair, such a permission check does not cost a lot of resources at all.

            – Namoshek
            Nov 23 '18 at 11:08
















          1














          You can use Storage::download('filename.xyz') instead of generating a URL with Storage::url('filename.xyu'). This will send the file as content of the response. It may be resource intensive for large files though.






          share|improve this answer
























          • Thanks @Namoshek! I updated my question with the solution I used based on your answer.

            – HelloWorld
            Nov 23 '18 at 10:51













          • Note about your comment in the solution So I check twice but that's not a problem because there is very low traffic (once a week or so): It is actually required for you to check the permissions twice (at least from what I got from the requirements). Otherwise a user with the permission to see or download the file could simply send the link to someone else. And to be fair, such a permission check does not cost a lot of resources at all.

            – Namoshek
            Nov 23 '18 at 11:08














          1












          1








          1







          You can use Storage::download('filename.xyz') instead of generating a URL with Storage::url('filename.xyu'). This will send the file as content of the response. It may be resource intensive for large files though.






          share|improve this answer













          You can use Storage::download('filename.xyz') instead of generating a URL with Storage::url('filename.xyu'). This will send the file as content of the response. It may be resource intensive for large files though.







          share|improve this answer












          share|improve this answer



          share|improve this answer










          answered Nov 22 '18 at 5:43









          NamoshekNamoshek

          3,0462819




          3,0462819













          • Thanks @Namoshek! I updated my question with the solution I used based on your answer.

            – HelloWorld
            Nov 23 '18 at 10:51













          • Note about your comment in the solution So I check twice but that's not a problem because there is very low traffic (once a week or so): It is actually required for you to check the permissions twice (at least from what I got from the requirements). Otherwise a user with the permission to see or download the file could simply send the link to someone else. And to be fair, such a permission check does not cost a lot of resources at all.

            – Namoshek
            Nov 23 '18 at 11:08



















          • Thanks @Namoshek! I updated my question with the solution I used based on your answer.

            – HelloWorld
            Nov 23 '18 at 10:51













          • Note about your comment in the solution So I check twice but that's not a problem because there is very low traffic (once a week or so): It is actually required for you to check the permissions twice (at least from what I got from the requirements). Otherwise a user with the permission to see or download the file could simply send the link to someone else. And to be fair, such a permission check does not cost a lot of resources at all.

            – Namoshek
            Nov 23 '18 at 11:08

















          Thanks @Namoshek! I updated my question with the solution I used based on your answer.

          – HelloWorld
          Nov 23 '18 at 10:51







          Thanks @Namoshek! I updated my question with the solution I used based on your answer.

          – HelloWorld
          Nov 23 '18 at 10:51















          Note about your comment in the solution So I check twice but that's not a problem because there is very low traffic (once a week or so): It is actually required for you to check the permissions twice (at least from what I got from the requirements). Otherwise a user with the permission to see or download the file could simply send the link to someone else. And to be fair, such a permission check does not cost a lot of resources at all.

          – Namoshek
          Nov 23 '18 at 11:08





          Note about your comment in the solution So I check twice but that's not a problem because there is very low traffic (once a week or so): It is actually required for you to check the permissions twice (at least from what I got from the requirements). Otherwise a user with the permission to see or download the file could simply send the link to someone else. And to be fair, such a permission check does not cost a lot of resources at all.

          – Namoshek
          Nov 23 '18 at 11:08




















          draft saved

          draft discarded




















































          Thanks for contributing an answer to Stack Overflow!


          • Please be sure to answer the question. Provide details and share your research!

          But avoid



          • Asking for help, clarification, or responding to other answers.

          • Making statements based on opinion; back them up with references or personal experience.


          To learn more, see our tips on writing great answers.




          draft saved


          draft discarded














          StackExchange.ready(
          function () {
          StackExchange.openid.initPostLogin('.new-post-login', 'https%3a%2f%2fstackoverflow.com%2fquestions%2f53423032%2flaravel-5-7-404-or-403-on-storage-app-private-whereas-it-works-on-storage-app%23new-answer', 'question_page');
          }
          );

          Post as a guest















          Required, but never shown





















































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown

































          Required, but never shown














          Required, but never shown












          Required, but never shown







          Required, but never shown







          Popular posts from this blog

          "Incorrect syntax near the keyword 'ON'. (on update cascade, on delete cascade,)

          Alcedinidae

          Origin of the phrase “under your belt”?