Commit 45796a52b3086a41339019fd3c2eb6dac29bf14f

Authored by Megan Watson
2 parents 76cbdb0b c0e37132

Merge branch 'edge' of git@github.com:ktgit/knowledgetree into edge

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  
... ...