vgrem / phpSPO

Microsoft 365 Library for PHP.
MIT License
358 stars 115 forks source link

Unable to upload files to Document folder in Shared Drive #106

Open Kkumarsantosh opened 6 years ago

Kkumarsantosh commented 6 years ago

Hello, I am trying to upload the file from my Linux server to the Shard Drive using the given below code

use Office365\PHP\Client\Runtime\Auth\AuthenticationContext; use Office365\PHP\Client\Runtime\Utilities\RequestOptions; use Office365\PHP\Client\SharePoint\ClientContext; use Office365\PHP\Client\Runtime\ClientRuntimeContext; use Office365\PHP\Client\SharePoint\SPList; use Office365\PHP\Client\SharePoint\File; use Office365\PHP\Client\SharePoint\FileCreationInformation;

require_once 'examples/bootstrap.php'; global $Settings;

try { $authCtx = new AuthenticationContext($webUrl); $authCtx->acquireTokenForUser($userName,$password); $ctx = new ClientContext($webUrl,$authCtx);

} catch (Exception $e) { echo 'Authentication failed: ', $e->getMessage(), "\n"; }

$localFilePath = "welcome.txt"; $targetFolderUrl = "sites/Ranascence/Shared Documents/Group_Projects/11_WISE";

$fileName = basename($localFilePath); $fileCreationInformation = new \Office365\PHP\Client\SharePoint\FileCreationInformation(); $fileCreationInformation->Content = file_get_contents($localFilePath); $fileCreationInformation->Url = $fileName;

$uploadFile = $ctx->getWeb()->getFolderByServerRelativeUrl($targetFolderUrl)->getFiles()->add($fileCreationInformation); $ctx->executeQuery(); print "File {$uploadFile->getProperty('ServerRelativeUrl')} has been uploaded\r\n";

But after executing i got an error Fatal error: Uncaught Exception: Access denied. You do not have permission to perform this action or access this resource. . . . . sharepoint\vendor\vgrem\php-spo\src\Runtime\OData\ODataRequest.php on line 113

Please suggest what mistake I have done

devcorrelator commented 6 years ago

I'm having the same issue. I can access the lists, download files, and get server information. I'm doing the same as you are above with the exception that I'm using NTLM. I only get this error when trying to upload a file (it's under 2 MB). I even had my SP guys set me up with a test site where I have Full Control, and I still get this error. When I try to do a File::saveBinary($ctx, $fileUri, $fileContent); I get a file doesn't exist error.

I've googled this error, and even followed the instructions for the WorkFlows. Similar to: https://sharepoint.stackexchange.com/questions/214935/apps-permission-request-xml-not-filled-when-accessing-appinv-aspx-again

And still no access. I even 'hacked' the Requests.php to dump the request/response stack (curl Verbose = true), and the payload. Everything there looks correct (btw, curl has a bug in 7.47 that is dropping the Content-Length header and causing aseperate 411 error from the SP server, I had to upgrade to 7.60 for that to go away).

Any help at this point would be greatly appreciated!! Edit: I should state that I don't think it's an issue with this library, but anyone in this Project would have a much better understanding of SharePoint than I do, and maybe can point me in the right direction.

devcorrelator commented 6 years ago

I would also like to include the code I'm using. I'm using the CakePHP 3.6 framework for some context, and here is a test command that i'm running that is reproducing my result.

<?php
/**
 * SharePointTestCommand
 */
namespace App\Command;

use ArrayObject;
use Cake\Console\Arguments;
use Cake\Console\Command;
use Cake\Console\ConsoleIo;
use Cake\Console\ConsoleOptionParser;
use Cake\Core\Configure;
use Office365\PHP\Client\Runtime\Auth\NetworkCredentialContext;
use Office365\PHP\Client\SharePoint\ClientContext;
use Office365\PHP\Client\SharePoint\FileCreationInformation;

/**
 * SharePoint Test
 *
 * Testing file uploading to Share Point Site.
 */
class SharePointTestCommand extends Command
{
    /**
     * Init method
     *
     * @return void
     */
    public function initialize()
    {
        parent::initialize();
    }

    /**
     * Builds the available options/args
     *
     * @param \Cake\Console\ConsoleOptionParser $parser Console options manager
     * @return \Cake\Console\ConsoleOptionParser $parser
     */
    public function buildOptionParser(ConsoleOptionParser $parser)
    {
        return $parser;
    }

    /**
     * Executes the command code
     *
     * @param \Cake\Console\Arguments $args Arguments passed from the command line
     * @param \Cake\Console\ConsoleIo $io IO interface to write to console.
     * @return void
     */
    public function execute(Arguments $args, ConsoleIo $io)
    {
        $uri = Configure::read('SP.uri_test');
        $filePath = TMP . 'HRV' . DS . urldecode(basename($uri));

        // the the server part
        list($server, $fileUri) = preg_split("/\\.test\.com\//", $uri);
        $server .= '.test.com';
        $fileUri = '/' . $fileUri;

        $authCtx = new NetworkCredentialContext(Configure::read('SP.username'), Configure::read('SP.password'));
        $authCtx->AuthType = CURLAUTH_NTLM; //NTML Auth schema
        $ctx = new ClientContext($server, $authCtx);
        $site = $ctx->getSite();
        $ctx->load($site); //load site settings

        $fileCreationInformation = new FileCreationInformation();
        $fileCreationInformation->Content = file_get_contents($filePath);
        $fileCreationInformation->Url = basename($filePath);
        $uploadFile = $ctx->getWeb()
            ->getFolderByServerRelativeUrl(dirname($fileUri))
            ->getFiles()
            ->add($fileCreationInformation);
        $ctx->executeQuery();
    }
}

Here is the request/response payload:

*   Trying [10.10.10.10]...
* TCP_NODELAY set
* Connected to [sp.test.com] ([10.10.10.10]) port 443 (#0)
* Initializing NSS with certpath: sql:/etc/pki/nssdb
*   CAfile: none
  CApath: none
* loaded libnssckbi.so
* skipping SSL peer certificate verification
* ALPN/NPN, server did not agree to a protocol
* SSL connection using [*********]
* Server certificate:
*       subject: CN=[sp.test.com],OU=Devices,OU=[*****],OU=[*****],O=[*****],C=[*****]
*       start date: Nov 21 20:17:55 2017 GMT
*       expire date: Nov 21 20:47:55 2020 GMT
*       common name: [sp.test.com]
*       issuer: CN=[*****],OU=Certification Authorities,OU=[*****],O=[*****],C=[*****]
* Server auth using NTLM with user '[username]'
> GET /_api/Site HTTP/1.1
Host: [sp.test.com]
Authorization: NTLM [****** Verified already ******]
Accept:application/json; OData=verbose
content-type:application/json; OData=verbose
Content-Length:0

< HTTP/1.1 401 Unauthorized
< Server: Microsoft-IIS/8.5
< WWW-Authenticate: NTLM [****** Verified already ******]
< SPRequestGuid: [******]
< request-id: [******]
< X-FRAME-OPTIONS: SAMEORIGIN
< SPRequestDuration: 2
< SPIisLatency: 0
< X-Powered-By: ASP.NET
< MicrosoftSharePointTeamServices: 16.0.0.4717
< X-Content-Type-Options: nosniff
< X-MS-InvokeApp: 1; RequireReadOnly
< Date: Wed, 08 Aug 2018 19:47:13 GMT
< Content-Length: 0
< Set-Cookie: asig_persistence=[******]; path=/
< Strict-Transport-Security: max-age=31536000; includeSubDomains
<
* Connection #0 to host [sp.test.com] left intact
* Issue another request to this URL: 'https://[sp.test.com]/_api/Site'
* Found bundle for host [sp.test.com]: 0x557d14bbf340 [can pipeline]
* Re-using existing connection! (#0) with host [sp.test.com]
* Connected to [sp.test.com] ([10.10.10.10]) port 443 (#0)
* Server auth using NTLM with user '[username]'
> GET /_api/Site HTTP/1.1
Host: [sp.test.com]
Authorization: NTLM [****** Verified already ******]
Accept:application/json; OData=verbose
content-type:application/json; OData=verbose
Content-Length:0

< HTTP/1.1 200 OK
< Cache-Control: private, max-age=0
< Transfer-Encoding: chunked
< Content-Type: application/json;odata=verbose;charset=utf-8
< Expires: Tue, 24 Jul 2018 19:47:13 GMT
< Last-Modified: Wed, 08 Aug 2018 19:47:13 GMT
< Server: Microsoft-IIS/8.5
< X-SharePointHealthScore: 0
< X-SP-SERVERSTATE: ReadOnly=0
< DATASERVICEVERSION: 3.0
< SPClientServiceRequestDuration: 13
< X-AspNet-Version: 4.0.30319
< SPRequestGuid: [******]
< request-id: [******]
< X-FRAME-OPTIONS: SAMEORIGIN
< Persistent-Auth: true
< X-Powered-By: ASP.NET
< MicrosoftSharePointTeamServices: 16.0.0.4717
< X-Content-Type-Options: nosniff
< X-MS-InvokeApp: 1; RequireReadOnly
< Date: Wed, 08 Aug 2018 19:47:13 GMT
< Strict-Transport-Security: max-age=31536000; includeSubDomains
<
* Connection #0 to host [sp.test.com] left intact

* Hostname [sp.test.com] was found in DNS cache
*   Trying [10.10.10.10]...
* TCP_NODELAY set
* Connected to [sp.test.com] ([10.10.10.10]) port 443 (#0)
*   CAfile: none
  CApath: none
* skipping SSL peer certificate verification
* ALPN/NPN, server did not agree to a protocol
* SSL connection using [*********]
* Server certificate:
*       subject: CN=[sp.test.com],OU=Devices,OU=[*****],OU=[*****],O=[*****],C=[*****]
*       start date: Nov 21 20:17:55 2017 GMT
*       expire date: Nov 21 20:47:55 2020 GMT
*       common name: [sp.test.com]
*       issuer: CN=[*****],OU=Certification Authorities,OU=[*****],O=[*****],C=[*****]
* Server auth using NTLM with user '[username]'
> POST /_api/contextinfo HTTP/1.1
Host: [sp.test.com]
Authorization: NTLM [****** Verified already ******]
Accept:application/json; OData=verbose
content-type:application/json; OData=verbose
Content-Length: 0

< HTTP/1.1 401 Unauthorized
< Server: Microsoft-IIS/8.5
< WWW-Authenticate: NTLM [****** Verified already ******]
< SPRequestGuid: [******]
< request-id: [******]
< X-FRAME-OPTIONS: SAMEORIGIN
< SPRequestDuration: 1
< SPIisLatency: 0
< X-Powered-By: ASP.NET
< MicrosoftSharePointTeamServices: 16.0.0.4717
< X-Content-Type-Options: nosniff
< X-MS-InvokeApp: 1; RequireReadOnly
< Date: Wed, 08 Aug 2018 19:47:13 GMT
< Content-Length: 0
< Set-Cookie: asig_persistence=[******]; path=/
< Strict-Transport-Security: max-age=31536000; includeSubDomains
<
* Connection #0 to host [sp.test.com] left intact
* Issue another request to this URL: 'https://[sp.test.com]/_api/contextinfo'
* Found bundle for host [sp.test.com]: 0x557d14e96eb0 [can pipeline]
* Re-using existing connection! (#0) with host [sp.test.com]
* Connected to [sp.test.com] ([10.10.10.10]) port 443 (#0)
* Server auth using NTLM with user '[username]'
> POST /_api/contextinfo HTTP/1.1
Host: [sp.test.com]
Authorization: NTLM [****** Verified already ******]
Accept:application/json; OData=verbose
content-type:application/json; OData=verbose
Content-Length:0
Expect: 100-continue

< HTTP/1.1 200 OK
< Cache-Control: private, max-age=0
< Transfer-Encoding: chunked
< Content-Type: application/json;odata=verbose;charset=utf-8
< Expires: Tue, 24 Jul 2018 19:47:13 GMT
< Last-Modified: Wed, 08 Aug 2018 19:47:13 GMT
< Server: Microsoft-IIS/8.5
< X-SharePointHealthScore: 0
< X-SP-SERVERSTATE: ReadOnly=0
< DATASERVICEVERSION: 3.0
< SPClientServiceRequestDuration: 10
< X-AspNet-Version: 4.0.30319
< SPRequestGuid: [******]
< request-id: [******]
< X-FRAME-OPTIONS: SAMEORIGIN
< Persistent-Auth: true
< X-Powered-By: ASP.NET
< MicrosoftSharePointTeamServices: 16.0.0.4717
< X-Content-Type-Options: nosniff
< X-MS-InvokeApp: 1; RequireReadOnly
< Date: Wed, 08 Aug 2018 19:47:13 GMT
< Strict-Transport-Security: max-age=31536000; includeSubDomains
<
* Connection #0 to host [sp.test.com] left intact

* Hostname [sp.test.com] was found in DNS cache
*   Trying [10.10.10.10]...
* TCP_NODELAY set
* Connected to [sp.test.com] ([10.10.10.10]) port 443 (#0)
*   CAfile: none
  CApath: none
* skipping SSL peer certificate verification
* ALPN/NPN, server did not agree to a protocol
* SSL connection using [*********]
* Server certificate:
*       subject: CN=[sp.test.com],OU=Devices,OU=[*****],OU=[*****],O=[*****],C=[*****]
*       start date: Nov 21 20:17:55 2017 GMT
*       expire date: Nov 21 20:47:55 2020 GMT
*       common name: [sp.test.com]
*       issuer: CN=[*****],OU=Certification Authorities,OU=[*****],O=[*****],C=[*****]
* Server auth using NTLM with user '[username]'
> POST /_api/Web/getfolderbyserverrelativeurl('%2Fsites%2Ftest%2FShared%2520Documents%2FTesters')/Files/add(overwrite=true,url='testing.zip') HTTP/1.1
Host: [sp.test.com]
Authorization: NTLM [****** Verified already ******]
X-RequestDigest:[*** verified ***]
Accept:application/json; OData=verbose
content-type:application/json; OData=verbose
Content-Length: 0

< HTTP/1.1 401 Unauthorized
< Server: Microsoft-IIS/8.5
< WWW-Authenticate: NTLM [****** Verified already ******]
< SPRequestGuid: [******]
< request-id: [******]
< X-FRAME-OPTIONS: SAMEORIGIN
< SPRequestDuration: 2
< SPIisLatency: 1
< X-Powered-By: ASP.NET
< MicrosoftSharePointTeamServices: 16.0.0.4717
< X-Content-Type-Options: nosniff
< X-MS-InvokeApp: 1; RequireReadOnly
< Date: Wed, 08 Aug 2018 19:47:13 GMT
< Content-Length: 0
< Set-Cookie: asig_persistence=[******]; path=/
< Strict-Transport-Security: max-age=31536000; includeSubDomains
<
* Connection #0 to host [sp.test.com] left intact
* Issue another request to this URL: 'https://[sp.test.com]/_api/Web/getfolderbyserverrelativeurl('%2Fsites%2Ftest%2FShared%2520Documents%2FTesters')/Files/add(overwrite=true,url='testing.zip')'
* Found bundle for host [sp.test.com]: 0x557d14fd70b0 [can pipeline]
* Re-using existing connection! (#0) with host [sp.test.com]
* Connected to [sp.test.com] ([10.10.10.10]) port 443 (#0)
* Server auth using NTLM with user '[username]'
> POST /_api/Web/getfolderbyserverrelativeurl('%2Fsites%2Ftest%2FShared%2520Documents%2FTesters')/Files/add(overwrite=true,url='testing.zip') HTTP/1.1
Host: [sp.test.com]
Authorization: NTLM [****** Verified already ******]
X-RequestDigest:[*** verified ***]
Accept:application/json; OData=verbose
content-type:application/json; OData=verbose
Content-Length:188

* upload completely sent off: 188 out of 188 bytes
< HTTP/1.1 401 Unauthorized
< Cache-Control: private, max-age=0
< Transfer-Encoding: chunked
< Content-Type: application/json;odata=verbose;charset=utf-8
< Expires: Tue, 24 Jul 2018 19:47:13 GMT
< Last-Modified: Wed, 08 Aug 2018 19:47:13 GMT
< Server: Microsoft-IIS/8.5
< X-SharePointHealthScore: 0
< X-SP-SERVERSTATE: ReadOnly=0
< DATASERVICEVERSION: 3.0
< SPClientServiceRequestDuration: 13
< X-AspNet-Version: 4.0.30319
< SPRequestGuid: [******]
< request-id: [******]
< X-RequestDigest:[*** verified ***]
< X-FRAME-OPTIONS: SAMEORIGIN
* NTLM handshake rejected
* Authentication problem. Ignoring this.
< WWW-Authenticate: NTLM
< X-Powered-By: ASP.NET
< MicrosoftSharePointTeamServices: 16.0.0.4717
< X-Content-Type-Options: nosniff
< X-MS-InvokeApp: 1; RequireReadOnly
< Date: Wed, 08 Aug 2018 19:47:13 GMT
< Strict-Transport-Security: max-age=31536000; includeSubDomains
<
* Connection #0 to host [sp.test.com] left intact
/vendor/vgrem/php-spo/src/Runtime/Utilities/Requests.php (line 32)
########## DEBUG ##########
'{"error":{"code":"-2147024891, System.UnauthorizedAccessException","message":{"lang":"en-US","value":"Access denied. You do not have permission to perform this action or access this resource."}}}'
devcorrelator commented 6 years ago

I figured it out!!! I never saw any documentation on this, maybe it's a SharePoint duh thing, but I didn't see any mention of it anywhere (I'm a SharePoint Noob). Anyway, the url for a sharepoint ser is broken into a structured way.

Example: https://sp.test.com/sites/test/SitePages/Home.aspx

The 'sites' is the site collection. The 'test' is the web site itself.

So, when trying to upload a file, instead of using this example url: https://[sp.test.com] /_api/ Web/getfolderbyserverrelativeurl('%2Fsites%2Ftest%2FShared%2520Documents%2FTesters')/Files/add(overwrite=true,url='testing.zip')

It needs to be this: https://[sp.test.com] /sites/test/_api/ Web/getfolderbyserverrelativeurl('%2FShared%2520Documents%2FTesters')/Files/add(overwrite=true,url='testing.zip')

So in the example for uploading a file to a sharepoint server, the code needs to look like this:

<?php
$filePath = '/path/to/file/test.zip';
$server = 'https://sp.test.com/sites/test'; // no ending slash
$fileUri = 'Shared Documents/test.zip';

$authCtx = new NetworkCredentialContext(Configure::read('SP.username'), Configure::read('SP.password'));
$authCtx->AuthType = CURLAUTH_NTLM; //NTML Auth schema
$ctx = new ClientContext($server, $authCtx);

$fileCreationInformation = new FileCreationInformation();
$fileCreationInformation->Content = file_get_contents($filePath);
$fileCreationInformation->Url = basename($filePath);
$uploadFile = $ctx->getWeb()
    ->getFolderByServerRelativeUrl(dirname($fileUri))
    ->getFiles()
    ->add($fileCreationInformation);
$ctx->executeQuery();
?>
irfankhan86004 commented 4 years ago

Hello

Lots of search but not found solution so can you please help me.

How to upload file in private site. Because when i will upload file on private site than it's throwing me error "Access denied. You do not have permission to perform this action or access this resource"

I m easily upload file in Communication Site but not in Team Site

So please help me.

saurith commented 4 years ago

Este código funciono perfecto para mi

require_once '../documentos/evidencias/api/vendor/autoload.php';

use Office365\SharePoint\ClientContext; use Office365\Runtime\Auth\ClientCredential; use Office365\Runtime\Auth\AuthenticationContext; use Office365\Runtime\Auth\NetworkCredentialContext;

use Office365\SharePoint\ListItem; use Office365\Runtime\Auth\UserCredentials; use Office365\SharePoint\FileCreationInformation;

//El problema esta en no colocar bien las rutas del site si esta mal sale error. $url = 'https://mysite.sharepoint.com/sites/SPNameFolder/subFolder/Subfolder';//Ruta principal del sitio no termina en"/" $userName = 'xxxxx@mysite.com'; $password = 'xxxxxxxxxx';

try {

$credentials = new UserCredentials($userName, $password);
//$credentials->AuthType = CURLAUTH_NTLM; //NTML Auth schema
$ctx = (new ClientContext($url))->withCredentials($credentials);

$filePath = 'world.xlsx';//Archivo local en el servidor

    //Folder destino no iniciar con "/" si lo colocas sale error 
    //tener en cuanta los espacios en blanco ej: "Documents Share"=Documents%20Share
$fileUri = 'Documenst%20Share/world.xlsx';

$fileCreationInformation = new FileCreationInformation();
$fileCreationInformation->Content = file_get_contents($filePath);
$fileCreationInformation->Url = basename($filePath);
$uploadFile = $ctx->getWeb()
    ->getFolderByServerRelativeUrl(dirname($fileUri))
    ->getFiles()
    ->add($fileCreationInformation);
$ctx->executeQuery();

} catch (Exception $e) { echo "Error:". $e->getMessage(), "\n"; }

domis86 commented 2 years ago

@devcorrelator it worked - thank you man :medal_military: