Commit 45796a52b3086a41339019fd3c2eb6dac29bf14f
Merge branch 'edge' of git@github.com:ktgit/knowledgetree into edge
Showing
5 changed files
with
167 additions
and
25 deletions
ktwebservice/KTUploadManager.inc.php
| ... | ... | @@ -134,6 +134,36 @@ class KTUploadManager |
| 134 | 134 | |
| 135 | 135 | return $tempfilename; |
| 136 | 136 | } |
| 137 | + | |
| 138 | + /** | |
| 139 | + * | |
| 140 | + * @param string $content file content NOT base64 encoded (may be string, may be binary) | |
| 141 | + * @param string $prefix [optional] | |
| 142 | + * @return $tempfilename the name of the temporary file created | |
| 143 | + */ | |
| 144 | + function store_file($content, $prefix= 'sa_') | |
| 145 | + { | |
| 146 | + $tempfilename = $this->get_temp_filename($prefix); | |
| 147 | + if (!is_writable($tempfilename)) | |
| 148 | + { | |
| 149 | + return new PEAR_Error("Cannot write to file: $tempfilename"); | |
| 150 | + } | |
| 151 | + | |
| 152 | + if (!$this->is_valid_temporary_file($tempfilename)) | |
| 153 | + { | |
| 154 | + return new PEAR_Error("Invalid temporary file: $tempfilename. There is a problem with the temporary storage path: $this->temp_dir."); | |
| 155 | + } | |
| 156 | + | |
| 157 | + $fp=fopen($tempfilename, 'wb'); | |
| 158 | + if ($fp === false) | |
| 159 | + { | |
| 160 | + return new PEAR_Error("Cannot write content to temporary file: $tempfilename."); | |
| 161 | + } | |
| 162 | + fwrite($fp, $content); | |
| 163 | + fclose($fp); | |
| 164 | + | |
| 165 | + return $tempfilename; | |
| 166 | + } | |
| 137 | 167 | |
| 138 | 168 | /** |
| 139 | 169 | * This tells the manager to manage a file that has been uploaded. | ... | ... |
lib/api/ktcmis/services/CMISObjectService.inc.php
| ... | ... | @@ -80,16 +80,16 @@ class CMISObjectService { |
| 80 | 80 | * @param array $properties Array of properties which must be applied to the created document object |
| 81 | 81 | * @param string $folderId The id of the folder which will be the parent of the created document object |
| 82 | 82 | * This parameter is optional IF unfilingCapability is supported |
| 83 | - * @param contentStream $contentStream optional content stream data | |
| 83 | + * @param string $contentStream optional content stream data - expected as a base64 encoded string | |
| 84 | 84 | * @param string $versioningState optional version state value: checkedout/major/minor |
| 85 | 85 | * @return string $objectId The id of the created folder object |
| 86 | 86 | */ |
| 87 | 87 | // TODO throw ConstraintViolationException if: |
| 88 | 88 | // value of any of the properties violates the min/max/required/length constraints |
| 89 | - // specified in the property definition in the Object-Type. | |
| 89 | + // specified in the property definition in the Object-Type. | |
| 90 | 90 | function createDocument($repositoryId, $typeId, $properties, $folderId = null, |
| 91 | 91 | $contentStream = null, $versioningState = null) |
| 92 | - { | |
| 92 | + { | |
| 93 | 93 | $objectId = null; |
| 94 | 94 | |
| 95 | 95 | // fetch type definition of supplied type and check for base type "document", if not true throw exception |
| ... | ... | @@ -196,11 +196,17 @@ class CMISObjectService { |
| 196 | 196 | // this check isn't strictly necessary; however it is needed for a repository which does not support content streams |
| 197 | 197 | if (!empty($contentStream)) |
| 198 | 198 | { |
| 199 | + // TODO consider checking whether content is encoded (currently we expect encoded) | |
| 200 | + // TODO choose between this and the alternative decode function (see CMISUtil class) | |
| 201 | + // The current one appears to be miles better (1/0/3 vs 14/4/57 on respective test files) | |
| 202 | + $contentStream = CMISUtil::decodeChunkedContentStream($contentStream); | |
| 203 | + | |
| 199 | 204 | // NOTE There is a function in CMISUtil to do this, written for the unit tests but since KTUploadManager exists |
| 200 | 205 | // and has more functionality which could come in useful at some point I decided to go with that instead |
| 201 | 206 | // (did not know this existed when I wrote the CMISUtil function) |
| 202 | 207 | $uploadManager = new KTUploadManager(); |
| 203 | - $tempfilename = $uploadManager->store_base64_file($contentStream, 'cmis_'); | |
| 208 | + // assumes already decoded from base64, should use store_base64_file if not | |
| 209 | + $tempfilename = $uploadManager->store_file($contentStream, 'cmis_'); | |
| 204 | 210 | |
| 205 | 211 | // metadata |
| 206 | 212 | $metadata = array(); | ... | ... |
lib/api/ktcmis/util/CMISUtil.inc.php
| ... | ... | @@ -298,10 +298,6 @@ class CMISUtil { |
| 298 | 298 | $object['properties']['ObjectId'] = array('type' => $properties->getFieldType('ObjectId'), |
| 299 | 299 | 'value' => $properties->getValue('ObjectId')); |
| 300 | 300 | |
| 301 | - | |
| 302 | - | |
| 303 | - | |
| 304 | - | |
| 305 | 301 | if (strtolower($properties->getValue('ObjectTypeId')) == 'document') |
| 306 | 302 | { |
| 307 | 303 | |
| ... | ... | @@ -400,6 +396,117 @@ class CMISUtil { |
| 400 | 396 | |
| 401 | 397 | return $temp; |
| 402 | 398 | } |
| 399 | + | |
| 400 | + // TODO run evaluations on each of the following two functions and determine which | |
| 401 | + // is generally more efficienct | |
| 402 | + | |
| 403 | + /** | |
| 404 | + * Alternative function for decoding chunked streams, this will decode in blocks of 4. | |
| 405 | + * Not sure which method is more efficient, this or the function below (this does not | |
| 406 | + * re-encode but I am working on removing that step for the other function.) | |
| 407 | + * | |
| 408 | + * NOTE The current one appears to be much slower (14/4/57 vs 1/0/3 on respective test files) | |
| 409 | + * | |
| 410 | + * @param string $contentStream the base64 encoded content stream | |
| 411 | + * @return string $decoded the decoded content stream | |
| 412 | + */ | |
| 413 | + static public function decodeContentStream($contentStream) | |
| 414 | + { | |
| 415 | + $decoded = ''; | |
| 416 | + | |
| 417 | + $contentStream = preg_replace('/\r?\n+/', '', $contentStream); | |
| 418 | + | |
| 419 | + // decode in chunks or 4 chars at a time | |
| 420 | + for($i = 0, $len = strlen($contentStream); $i < $len; $i += 4) { | |
| 421 | + $decoded .= base64_decode(substr($contentStream, $i, 4)); | |
| 422 | + } | |
| 423 | + | |
| 424 | + return $decoded; | |
| 425 | + } | |
| 426 | + | |
| 427 | + /** | |
| 428 | + * Checks the contentStream and ensures that it is a correct base64 string; | |
| 429 | + * This is purely for clients such as CMISSpaces breaking the content into | |
| 430 | + * chunks before base64 encoding. | |
| 431 | + * | |
| 432 | + * If the stream is chunked, it is decoded in chunks and sent back as a single stream. | |
| 433 | + * If it is not chunked it is decoded as is and sent back as a single stream. | |
| 434 | + * | |
| 435 | + * NOTE this function and the above need to be checked for efficiency. | |
| 436 | + * The current one appears to be miles better (1/0/3 vs 14/4/57 on respective test files) | |
| 437 | + * | |
| 438 | + * @param object $contentStream | |
| 439 | + * @return string decoded | |
| 440 | + */ | |
| 441 | + static public function decodeChunkedContentStream($contentStream) | |
| 442 | + { | |
| 443 | + // check the content stream for any lines of unusual length (except the last line, which can be any length) | |
| 444 | + $count = -1; | |
| 445 | + $length = 0; | |
| 446 | + $b64String = ''; | |
| 447 | + $outputStream = ''; | |
| 448 | + $decode = array(); | |
| 449 | + $chunks = 1; | |
| 450 | + $decoded = ''; | |
| 451 | + $chunked = ''; | |
| 452 | + | |
| 453 | + $splitStream = explode("\n", $contentStream); | |
| 454 | + foreach ($splitStream as $line) | |
| 455 | + { | |
| 456 | + $curlen = strlen($line); | |
| 457 | + | |
| 458 | + if ($length == 0) { | |
| 459 | + $length = $curlen; | |
| 460 | + } | |
| 461 | + | |
| 462 | + // if we find one we know that we must split the line here and end the previous base64 string | |
| 463 | + if ($curlen > $length) | |
| 464 | + { | |
| 465 | + // check for a new chunk | |
| 466 | + // either we have an equals sign (or two) | |
| 467 | + if (preg_match('/([^=]*={0,2})(.*)/', $line, $matches)) | |
| 468 | + { | |
| 469 | + $lastChunk = $matches[1]; | |
| 470 | + $nextChunk = $matches[2]; | |
| 471 | + } | |
| 472 | + // or we need to try by line length | |
| 473 | + else { | |
| 474 | + $lastChunk = substr($line, 0, $curlen - $length); | |
| 475 | + $nextChunk = substr($line, $curlen - $length); | |
| 476 | + } | |
| 477 | + | |
| 478 | + $decode[++$count] = $b64String . $lastChunk; | |
| 479 | + | |
| 480 | + $b64String = $nextChunk . "\n"; | |
| 481 | + $length = strlen($nextChunk); | |
| 482 | + | |
| 483 | + ++$chunks; | |
| 484 | + } | |
| 485 | + else { | |
| 486 | + $b64String .= $line . "\n"; | |
| 487 | + } | |
| 488 | + } | |
| 489 | + | |
| 490 | + // anything left over | |
| 491 | + if (!empty($b64String)) { | |
| 492 | + $decode[] = $b64String; | |
| 493 | + } | |
| 494 | + | |
| 495 | + if ($chunks > 1) | |
| 496 | + { | |
| 497 | + foreach($decode as $code) { | |
| 498 | + // decode, append to output to be re-encoded | |
| 499 | + $chunked .= base64_decode($code); | |
| 500 | + } | |
| 501 | + | |
| 502 | + $decoded = $chunked; | |
| 503 | + } | |
| 504 | + else { | |
| 505 | + $decoded = base64_decode($decode[0]); | |
| 506 | + } | |
| 507 | + | |
| 508 | + return $decoded; | |
| 509 | + } | |
| 403 | 510 | |
| 404 | 511 | } |
| 405 | 512 | ... | ... |
webservice/atompub/cmis/KT_cmis_atom_server.services.inc.php
| ... | ... | @@ -103,10 +103,17 @@ class KT_cmis_atom_service_folder extends KT_atom_service { |
| 103 | 103 | // determine whether this is a folder or a document create |
| 104 | 104 | // document create will have a content tag <atom:content> or <content> containing base64 encoding of the document |
| 105 | 105 | $content = KT_cmis_atom_service_helper::getAtomValues($this->parsedXMLContent['@children'], 'content'); |
| 106 | - if (is_null($content)) | |
| 106 | + | |
| 107 | + // check content for weird chars | |
| 108 | + $matches = array(); | |
| 109 | + preg_match('/[^\w\d\/\+\n]*/', $content, $matches); | |
| 110 | + | |
| 111 | + if (is_null($content)) { | |
| 107 | 112 | $type = 'folder'; |
| 108 | - else | |
| 113 | + } | |
| 114 | + else { | |
| 109 | 115 | $type = 'document'; |
| 116 | + } | |
| 110 | 117 | |
| 111 | 118 | $cmisObjectProperties = KT_cmis_atom_service_helper::getCmisProperties($this->parsedXMLContent['@children']['cmis:object'] |
| 112 | 119 | [0]['@children']['cmis:properties'] |
| ... | ... | @@ -124,20 +131,17 @@ class KT_cmis_atom_service_folder extends KT_atom_service { |
| 124 | 131 | |
| 125 | 132 | if ($typeId != 'Unknown') |
| 126 | 133 | { |
| 134 | + /*$f = fopen('c:\kt-stuff\here.txt', 'w'); | |
| 135 | + fwrite($f, 'fgfgfgfg'); | |
| 136 | + fclose($f);*/ | |
| 127 | 137 | $this->setStatus(self::STATUS_CREATED); |
| 128 | -// if ($type == 'folder') | |
| 129 | -// { | |
| 130 | - $feed = KT_cmis_atom_service_helper::getObjectFeed($ObjectService, $repositoryId, $newObjectId, 'POST'); | |
| 131 | -// } | |
| 132 | -// else | |
| 133 | -// { | |
| 134 | -// $NavigationService = new NavigationService(KT_cmis_atom_service_helper::getKt()); | |
| 135 | -// $cmisEntry = $ObjectService->getProperties($repositoryId, $folderId, false, false); | |
| 136 | -// $feed = $this->getFolderChildrenFeed($NavigationService, $repositoryId, $folderId, $cmisEntry['properties']['Name']['value'], 'POST'); | |
| 137 | -// } | |
| 138 | + $feed = KT_cmis_atom_service_helper::getObjectFeed($ObjectService, $repositoryId, $newObjectId, 'POST'); | |
| 138 | 139 | } |
| 139 | 140 | else |
| 140 | 141 | { |
| 142 | + /*$f = fopen('c:\kt-stuff\failed.txt', 'w'); | |
| 143 | + fwrite($f, 'fgfgfgfg'); | |
| 144 | + fclose($f);*/ | |
| 141 | 145 | $feed = KT_cmis_atom_service_helper::getErrorFeed($this, self::STATUS_SERVER_ERROR, $newObjectId['message']); |
| 142 | 146 | } |
| 143 | 147 | ... | ... |
webservice/atompub/cmis/index.php
| ... | ... | @@ -72,11 +72,6 @@ if(!KT_atom_HTTPauth::isLoggedIn()) { |
| 72 | 72 | KT_atom_HTTPauth::login('KnowledgeTree DMS', 'You must authenticate to enter this realm'); |
| 73 | 73 | } |
| 74 | 74 | |
| 75 | -//$username = $_SERVER['PHP_AUTH_USER']; | |
| 76 | -//$password = $_SERVER['PHP_AUTH_PW']; | |
| 77 | -//// fetch user name and password (check auth include for proper method) | |
| 78 | -//KT_cmis_atom_service_helper::login($username, $password); | |
| 79 | - | |
| 80 | 75 | //Start the AtomPubProtocol Routing Engine |
| 81 | 76 | $APP = new KT_cmis_atom_server(); |
| 82 | 77 | ... | ... |