<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>GroupDocs Blog</title>
	<atom:link href="http://groupdocs.com/blog/feed" rel="self" type="application/rss+xml" />
	<link>http://groupdocs.com/blog</link>
	<description></description>
	<lastBuildDate>Mon, 20 May 2013 12:41:10 +0000</lastBuildDate>
	<language>en</language>
	<sy:updatePeriod>hourly</sy:updatePeriod>
	<sy:updateFrequency>1</sy:updateFrequency>
	<generator>http://wordpress.org/?v=3.3.1</generator>
		<item>
		<title>Annotate PDF, Word and Other Files Easily from Within Your Concrete5 Sites</title>
		<link>http://groupdocs.com/blog/annotate-pdf-word-and-other-files-easily-from-within-your-concrete5-sites</link>
		<comments>http://groupdocs.com/blog/annotate-pdf-word-and-other-files-easily-from-within-your-concrete5-sites#comments</comments>
		<pubDate>Mon, 20 May 2013 08:18:42 +0000</pubDate>
		<dc:creator>Derek</dc:creator>
				<category><![CDATA[GroupDocs Annotation]]></category>
		<category><![CDATA[GroupDocs Annotation Plugin]]></category>
		<category><![CDATA[Annotate]]></category>
		<category><![CDATA[Document annotation]]></category>
		<category><![CDATA[document management]]></category>
		<category><![CDATA[GroupDocs Annotate]]></category>
		<category><![CDATA[Online Document Annotation]]></category>
		<category><![CDATA[online document management system]]></category>

		<guid isPermaLink="false">http://groupdocs.com/blog/?p=2261</guid>
		<description><![CDATA[We are glad to announce the launch of a GroupDocs Annotation plugin for Concrete5. This plugin allows you to embed documents to Concrete5 pages. The GroupDocs Annotation plugin adds annotation tools to the documents you embed: perfect for collaborative review. Annotate PDF, Word, or other files, add comments and get reviews in real time. Share [...]]]></description>
			<content:encoded><![CDATA[<p>We are glad to announce the launch of a <strong><a href="http://groupdocs.com/marketplace/plugins/annotation/concrete5" rel="nofollow">GroupDocs Annotation plugin</a></strong> for Concrete5. This plugin allows you to embed documents to Concrete5 pages. The GroupDocs Annotation plugin adds <a href="http://groupdocs.com/apps/annotation/whats-new" rel="nofollow"><strong>annotation tools</strong></a> to the documents you embed: perfect for collaborative review. <strong>Annotate PDF</strong>, Word, or other files, add comments and get reviews in real time. Share documents online and use this platform-independent app to bridge communication gaps between teams.</p>
<p>GroupDocs Annotation facilitates consolidated feedback and saves time on PDF annotation, Word annotation, and Excel annotation.</p>
<h2><a name="AnnotatePDF,WordandOtherFilesEasilyfromWithinYourConcrete5Sites-WhatisGroupDocsAnnotation?"></a>What is GroupDocs Annotation?</h2>
<p><a href="http://groupdocs.com/apps/annotation" rel="nofollow"><strong>GroupDocs Annotation</strong></a> is a web-based document collaboration application. It helps you review and annotate documents online and is useful for distributed teams. Instead of using emails or marked-up paper copies of documents, collect everyone's comments in one place and resolve conflicting suggestions quickly.</p>
<p>You can <strong>annotate PDF</strong>, and other types of files, from anywhere as long as you have an Internet connection. GroupDocs Annotation supports most popular file formats and the powerful dashboard gives you access to the following <strong><a href="http://groupdocs.com/apps/annotation/features" rel="nofollow">features</a></strong>:</p>
<ul>
<li>Add area notes, text notes, and strikeouts.</li>
<li>Annotate images.</li>
<li>Interact in real-time.</li>
<li>Manage contacts and use other GroupDocs apps.</li>
<li>Helps documentation/marketing teams to produce deliverables on time.</li>
</ul>
<p>GroupDocs Annotation and a web browser is all you need to <strong>annotate PDF</strong> and other files.</p>
<p>GroupDocs Annotation lets you add comments to documents, and share both document and comments with your colleagues. For example, share a brochure PDF and ask your colleagues to annotate PDF online. Because it supports so many file formats, GroupDocs Annotation is used for online PDF annotation, online Word annotation, online image annotation and so on.</p>
<p>The GroupDocs Annotation plugin for Concrete5 delivers these features for Concrete5 websites.</p>
<h3><a name="AnnotatePDF,WordandOtherFilesEasilyfromWithinYourConcrete5Sites-InstallingthePlugin"></a>Installing the Plugin</h3>
<p>It takes only minutes to install GroupDocs Annotation to a Concrete5 website:</p>
<ol>
<li>Save the annotation package folder into the local Concrete5 directory.</li>
<li>Go to <strong>Dashboard</strong>, then <strong>Extend Concrete 5</strong>.</li>
<li>Check that GroupDocs Annotation is listed in the waiting Installation section.</li>
<li>Click <strong>Install</strong>.`</li>
<li>Configure settings.</li>
<li>Embed the document.</li>
</ol>
<div id="attachment_2277" class="wp-caption alignnone" ><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/Installing-GroupDocs-Annotation-plugin-for-Concrete55.png"><img class="size-full wp-image-2277" style="border: 1px solid black;" title="Installing GroupDocs Annotation plugin in Concrete5" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/Installing-GroupDocs-Annotation-plugin-for-Concrete55.png" alt="Installing GroupDocs Annotation plugin for Concrete55 Annotate PDF, Word and Other Files Easily from Within Your Concrete5 Sites" width="599" height="435" /></a><p class="wp-caption-text">Installing GroupDocs Annotation plugin in Concrete5</p></div>
<p>Now, share the document online with your colleagues and let them <strong>annotate PDF</strong>, Word and other files. This facilitates real-time reviewing and saves time and energy.</p>
<div id="attachment_2280" class="wp-caption alignnone" ><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/Annotation-sample-document-display4.png"><img class="size-full wp-image-2280 " style="border: 1px solid black;" title="Annotation sample document display" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/Annotation-sample-document-display4.png" alt="Annotation sample document display4 Annotate PDF, Word and Other Files Easily from Within Your Concrete5 Sites" width="598" height="311" /></a><p class="wp-caption-text">Annotation sample document display</p></div>
<p>Refer to <strong><a href="http://groupdocs.com/docs/display/annotation/Integrating+GroupDocs+Annotation+Plugin+with+Concrete5" rel="nofollow">Integrating Annotation plugin with Concrete5</a></strong> for more information.</p>
<h2><a name="AnnotatePDF,WordandOtherFilesEasilyfromWithinYourConcrete5Sites-ReviewingDocuments"></a>Reviewing Documents</h2>
<p>Individuals review documents in different ways. Some like to <strong><a href="http://groupdocs.com/apps/annotation" rel="nofollow">add notes, highlight text or draw lines</a></strong> on the document. How you annotate is an individual style statement as well as a habit. GroupDocs Annotation packages all these options together and delivers one powerful tool that lets users annotate the way they find most efficient.</p>
<p>GroupDocs Annotation is software and platform independent. This means that you can collaborate, finalize, and publish documents from within a web-browser. Even better, GroupDocs Annotation is flexible enough to adapt to different requirements. So whether you need to annotate PDF online, or work with Word files online, GroupDocs Annotation works.</p>
<p>If you're unfamiliar with GroupDocs Annotation, <strong><a href="http://groupdocs.com/apps/annotation/try-it-now" rel="nofollow">try it now</a></strong>. Simply install the plugin and enjoy the benefits of PDF annotation, Excel annotation and many others in a single application. You will see the benefits from day one!</p>
<p>GroupDocs' file compatibility makes it a preferred choice with our customers. GroupDocs provides you with all the document reviewing and collaborating solutions you need.</p>
<p>Your feedback is valuable to us and we are open to your suggestions. Please post your query, problem or suggestion in the <strong><a href="http://community.groupdocs.com/Forums/Default.aspx" rel="nofollow" class="broken_link">GroupDocs Forum</a></strong> or speak to an <a href="http://groupdocs.com/" rel="nofollow"><strong>Online Support Agent</strong></a>. We will keep you posted on all GroupDocs enhancements.</p>
]]></content:encoded>
			<wfw:commentRss>http://groupdocs.com/blog/annotate-pdf-word-and-other-files-easily-from-within-your-concrete5-sites/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to Upload PHP Project to Heroku? &#8211; Advanced Steps</title>
		<link>http://groupdocs.com/blog/how-to-upload-php-project-to-heroku-advanced-steps</link>
		<comments>http://groupdocs.com/blog/how-to-upload-php-project-to-heroku-advanced-steps#comments</comments>
		<pubDate>Fri, 17 May 2013 14:04:35 +0000</pubDate>
		<dc:creator>Derek</dc:creator>
				<category><![CDATA[Tech Blog]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[GroupDocs PHP SDK]]></category>
		<category><![CDATA[Heroku]]></category>
		<category><![CDATA[heroku toolbelt]]></category>

		<guid isPermaLink="false">http://groupdocs.com/blog/?p=2245</guid>
		<description><![CDATA[In the previous article, we learned how to create a new PHP project on Heroku. But sometimes our project requires additional extensions that do not exist in the Heroku PHP configuration. So we need to find out how to create and install extensions for PHP on Heroku. In this post, I'll show you these advanced [...]]]></description>
			<content:encoded><![CDATA[<p>In the <a href="http://groupdocs.com/blog/how-to-upload-php-project-to-heroku" rel="nofollow">previous article,</a> we learned how to create a new PHP project on Heroku. But sometimes our project requires additional extensions that do not exist in the Heroku PHP configuration. So we need to find out how to create and install extensions for PHP on Heroku.</p>
<p>In this post, I'll show you these advanced steps, and create a PHP project on Heroku with the <a href="https://github.com/groupdocs/groupdocs-php" rel="nofollow">GroupDocs PHP SDK Api Samples</a> application.</p>
<h2><a name="Article18-HowtouploadPHPprojecttoHerokuadvancedsteps-Preparation"></a>Preparation</h2>
<p>All required preparation are described in <a href="http://groupdocs.com/blog/how-to-upload-php-project-to-heroku" rel="nofollow">previous article</a>. Also, we need two PHP extensions such as Curl and Sockets that are used in our PHP Samples application.</p>
<h2><a name="Article18-HowtouploadPHPprojecttoHerokuadvancedsteps-BuildanextensiononHeroku."></a>Build an extension on Heroku.</h2>
<p>This can be done by opening a Heroku console, download the PHP source-code and compile the extension, then copying it over.</p>
<p>To create the Curl extension:</p>
<ol>
<li>Open console and cd to root folder of your API.</li>
<li><tt>&gt;heroku run bash </tt><tt><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/heroku-run-bash.png"><img class="alignnone size-full wp-image-2250" title="heroku run bash" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/heroku-run-bash.png" alt="heroku run bash How to Upload PHP Project to Heroku?   Advanced Steps"  /></a></tt></li>
<li><tt>$ mkdir tmp</tt></li>
<li><tt>$cd tmp</tt></li>
<li><tt>git clonehttps://github.com/php/php-src.git </tt><tt><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/git-clonehttps.png"><img class="alignnone size-full wp-image-2251" title="git clonehttps" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/git-clonehttps.png" alt="git clonehttps How to Upload PHP Project to Heroku?   Advanced Steps"  /></a></tt></li>
<li><tt>$cd php-src</tt></li>
<li><tt>$ cd ext/curl</tt></li>
<li><tt>$ /app/php/bin/phpize </tt><tt><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/phpize.png"><img class="alignnone size-full wp-image-2252" title="phpize" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/phpize.png" alt="phpize How to Upload PHP Project to Heroku?   Advanced Steps"  /></a></tt></li>
<li><tt>$ ./configure --with-php-config=/app/php/bin/php-config </tt><tt><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/Configure.png"><img class="alignnone size-full wp-image-2253" title="Configure" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/Configure.png" alt="Configure How to Upload PHP Project to Heroku?   Advanced Steps"  /></a></tt></li>
<li><tt>$ make</tt></li>
<li><tt>$ cd modules</tt></li>
</ol>
<p>To create the Sockets extension, take the same steps.</p>
<p>Don't close the console. We will use it for the next steps.</p>
<h2><a name="Article18-HowtouploadPHPprojecttoHerokuadvancedsteps-DownloadlibfromHeroku."></a>Download lib from Heroku.</h2>
<p>Now we have compiled the extension, but this file is on the Heroku server and we need it in our API.</p>
<p>To get the file from the server and add it to the API, we can create an empty repo on GitHub and clone it to the temp folder in which we compile the extension. Then copy the extension file and push it to GitHub. After that, you can download it from GitHub to the <strong>lib</strong> folder and push it to Heroku.</p>
<p>Lets see this logic in practical steps by adding the Curl extension:</p>
<ol>
<li>In the mudel folder, <tt>$ ssh-keygen -t rsa</tt></li>
<li><tt>$ cat /app/.ssh/id_rsa.pub</tt><br />
This command shows your ssh key file content in the console. Copy it.</li>
<li>Add your SSH key to GitHub.</li>
<li><tt>$ git clone yourreposshurl</tt></li>
<li><tt>$ mv curl.so cloned folder name</tt></li>
<li><tt>$ cd cloned folder</tt></li>
<li><tt>$ git add .</tt></li>
<li><tt>$ git commit -m "adding extension"</tt></li>
<li><tt>$ git push origin master</tt></li>
<li><tt>$ exit</tt></li>
</ol>
<p>Now we have our extension file in the GitHub repository and we can download it.</p>
<p>To add the Sockets extension, take the same steps.</p>
<h2><a name="Article18-HowtouploadPHPprojecttoHerokuadvancedsteps-Addlibandphp.inifiletoyourappanduploadthemtoHeroku"></a>Add lib and php.ini file to your app and upload them to Heroku</h2>
<p>In the root folder of the API, create a <strong>lib</strong> folder and save the downloaded file there. And there's only one thing left to do: create a <strong>php.ini</strong> file in the root folder of the API that points to that extension. The changes are committed. To do all this open console and:</p>
<ol>
<li><tt>cd</tt> to the API root folder</li>
<li><tt>&gt;mkdir lib</tt></li>
<li><tt>cd</tt> to the folder where the downloaded extension folder is.</li>
<li><tt>&gt;mv curl.so rootfolderapi/lib</tt></li>
<li><tt>cd</tt> to the API root folder.</li>
<li><tt>$ echo extension = /app/www/lib/curl.so &gt; php.ini</tt></li>
<li><tt>$ git add .</tt></li>
<li><tt>$ git commit -m "adding extension"</tt></li>
<li><tt>$ git push origin master</tt></li>
</ol>
<p>That's all, your new PHP application is ready to use on Heroku. Enjoy!</p>
]]></content:encoded>
			<wfw:commentRss>http://groupdocs.com/blog/how-to-upload-php-project-to-heroku-advanced-steps/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to upload PHP project to Heroku?</title>
		<link>http://groupdocs.com/blog/how-to-upload-php-project-to-heroku</link>
		<comments>http://groupdocs.com/blog/how-to-upload-php-project-to-heroku#comments</comments>
		<pubDate>Fri, 10 May 2013 11:40:59 +0000</pubDate>
		<dc:creator>Derek</dc:creator>
				<category><![CDATA[Tech Blog]]></category>
		<category><![CDATA[git]]></category>
		<category><![CDATA[GroupDocs PHP SDK]]></category>
		<category><![CDATA[Heroku]]></category>
		<category><![CDATA[heroku toolbelt]]></category>

		<guid isPermaLink="false">http://groupdocs.com/blog/?p=2223</guid>
		<description><![CDATA[Heroku is a great opportunity for developers to try and test their code in a production environment. Originally created for Ruby projects, Heroku now supports Ruby, Java, Python and even PHP. Heroku's PHP project support is an undocumented feature so some additional skills are required do deploy such a project. In this post, I'll show [...]]]></description>
			<content:encoded><![CDATA[<p>Heroku is a great opportunity for developers to try and test their code in a production environment. Originally created for Ruby projects, Heroku now supports Ruby, Java, Python and even PHP. Heroku's PHP project support is an undocumented feature so some additional skills are required do deploy such a project.</p>
<p>In this post, I'll show you the methods to create a PHP project on Heroku with the <a href="https://github.com/groupdocs/groupdocs-php" rel="nofollow">GroupDocs PHP SDK Api Samples</a> application.</p>
<h2><a name="Article17-HowtouploadPHPprojecttoHeroku-Preparation"></a>Preparation</h2>
<ul>
<li>To get the PHP samples, you first need to clone the entire PHP SDK repository:<br />
<tt>$ git clone git://github.com/groupdocs/groupdocs-php.git</tt></li>
</ul>
<ul>
<li>Then go to the examples directory (<strong>$ cd groupdocs-php/examples</strong>) and copy the <strong>api-samples</strong> folder to the location where you want to create a Heroku project.</li>
</ul>
<p><strong>Note</strong>: Before uploading PHP API samples to Heroku, you need to update the PHP SDK in the API Samples project. You can check out our previous posts to find information on how to do this, for example, <a href="http://groupdocs.com/blog/how-to-use-groupdocs-php-sdk-with-composer-or-a-built-in-autoloader" rel="nofollow">How to use GroupDocs PHP SDK with Composer or a Built-in Autoloader</a>.</p>
<h2><a name="Article17-HowtouploadPHPprojecttoHeroku-CreatingaHerokuproject"></a>Creating a Heroku project</h2>
<p>To create a Heroku project, create a local repository with git (the example below assumes that you have Heroku toolbelt installed).</p><pre class="crayon-plain-tag">$ cd api-samples
$ git init
$ heroku create yourapplicationname</pre><p>Note that in some guides, you might see the option <tt>-</tt><tt><del>stack cedar</del></tt> in the <tt>heroku create</tt> command. This option is not required anymore. <tt>-stack cedar</tt> is now the default for new apps on Heroku.</p>
<p>If you've done everything correctly, Heroku creates a new application and adds a new remote (with the same name – heroku) to your local repository. You can check this with the command:<br />
<tt>$ git remote --v</tt></p>
<p>You should see Heroku remote records with remote URLs for pull and push.</p>
<p>Now you can push your local repository to Heroku:</p>
<div>
<div>
<pre class="crayon-plain-tag">$ git push heroku master</pre>
</div>
</div>
<p>All your commits from the local repository are pushed to Heroku. Heroku detects the type of your application – PHP project in our case – and starts the appropriate server to host the app.</p>
<p>If you use only standard PHP libraries, you can immediately start working with your new application on Heroku:</p>
<div>
<div>
<pre class="crayon-plain-tag">$ heroku apps open</pre>
</div>
</div>
<p>But if your project/app requires a non-standard library (like the PHP API samples project), then you'll have problems with Heroku if you try to use it immediately. To be able to use such extensions, you need to perform additional steps:</p>
<ol>
<li>Build an extension on Heroku.</li>
<li>Download lib from Heroku.</li>
<li>Add lib and <strong>php.ini</strong> file to your app and upload them to Heroku.</li>
</ol>
<p>I'll show you how to perform those advanced steps in the next blog post.</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://groupdocs.com/blog/how-to-upload-php-project-to-heroku/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>GroupDocs Newsletter May 2013: GroupDocs Comparison CMS Integration and GroupDocs Viewer for .NET</title>
		<link>http://groupdocs.com/blog/groupdocs-newsletter-may-2013-groupdocs-comparison-cms-integration-and-groupdocs-viewer-for-net</link>
		<comments>http://groupdocs.com/blog/groupdocs-newsletter-may-2013-groupdocs-comparison-cms-integration-and-groupdocs-viewer-for-net#comments</comments>
		<pubDate>Fri, 10 May 2013 11:39:53 +0000</pubDate>
		<dc:creator>Derek</dc:creator>
				<category><![CDATA[Announcement]]></category>
		<category><![CDATA[Newsletters]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[document collaboration]]></category>
		<category><![CDATA[document management]]></category>
		<category><![CDATA[GroupDocs Annotate]]></category>
		<category><![CDATA[GroupDocs Signature]]></category>
		<category><![CDATA[GroupDocs Viewer]]></category>
		<category><![CDATA[GroupDocs Viewer Plugin]]></category>
		<category><![CDATA[online document management system]]></category>
		<category><![CDATA[online document viewer]]></category>
		<category><![CDATA[View documents online]]></category>

		<guid isPermaLink="false">http://groupdocs.com/blog/?p=2165</guid>
		<description><![CDATA[GroupDocs extended the reach of its powerful Comparison app to a whole host of CMSs last month, in addition to enhancing its app UIs. May is an exciting month for GroupDocs as we're about to launch GroupDocs Viewer for .NET, a downloadable version of our online document viewer for the .NET platform. This lets you use [...]]]></description>
			<content:encoded><![CDATA[<p><a href="http://groupdocs.com/" target="_self">GroupDocs</a> extended the reach of its powerful <a href="http://groupdocs.com/apps/comparison" target="_self">Comparison app</a> to a whole host of CMSs last month, in addition to enhancing its app UIs.</p>
<p>May is an exciting month for GroupDocs as we're about to launch GroupDocs Viewer for .NET, a downloadable version of our online document viewer for the .NET platform. This lets you use <a href="http://groupdocs.com/apps/viewer" target="_self">GroupDocs Viewer</a> as part of your .NET systems.</p>
<p>Tabular data merging in Assembly and a pressure-sensitive signing pad for <a href="http://groupdocs.com/apps/signature" target="_self">GroupDocs Signature</a> are in the offing. In addition, you can expect more enhancements to all of our app UIs in the coming weeks.</p>
<h2><a href="http://groupdocs.com/blog/wp-content/uploads/2013/02/New-Features.png"><img title="New Features" src="http://groupdocs.com/blog/wp-content/uploads/2013/02/New-Features.png" alt="New Features GroupDocs Newsletter May 2013: GroupDocs Comparison CMS Integration and GroupDocs Viewer for .NET"  /></a></h2>
<p>This month, we've made enhancements to several GroupDocs apps, launched various plugins for CMSs and updated the <a href="http://groupdocs.com/api" target="_self">GroupDocs SDKs</a>.</p>
<p><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Viewer-image.png"><img class="alignnone size-full wp-image-2179" title="GD Viewer image" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Viewer-image.png" alt="GD Viewer image GroupDocs Newsletter May 2013: GroupDocs Comparison CMS Integration and GroupDocs Viewer for .NET"  /></a></p>
<ul>
<li>Usability enhancements.</li>
</ul>
<p><strong title="Annotation icon"><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/GS-Annotation-heading-image.png"><img class="alignnone size-full wp-image-2167" title="GD Annotation heading image" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/GS-Annotation-heading-image.png" alt="GS Annotation heading image GroupDocs Newsletter May 2013: GroupDocs Comparison CMS Integration and GroupDocs Viewer for .NET"  /></a></strong></p>
<ul>
<li>Cursor based real-time pointer improvements.</li>
</ul>
<div>
<p><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Assembly-image1.png"><img class="alignnone size-full wp-image-2202" title="GD Assembly image" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Assembly-image1.png" alt="GD Assembly image1 GroupDocs Newsletter May 2013: GroupDocs Comparison CMS Integration and GroupDocs Viewer for .NET"  /></a></p>
<ul>
<li>WYSIWYG support for questionnaire answers and enhanced integration options.</li>
</ul>
</div>
<div>
<p><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Comparison-image1.png"><img class="alignnone size-full wp-image-2204" title="GD Comparison image" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Comparison-image1.png" alt="GD Comparison image1 GroupDocs Newsletter May 2013: GroupDocs Comparison CMS Integration and GroupDocs Viewer for .NET"  /></a></p>
<ul>
<li>Addition of embedded comparison results.</li>
<li>Roll-out of Comparison v2.0 with results summary list.</li>
</ul>
</div>
<p><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Signature-image.png"><img class="alignnone size-full wp-image-2183" title="GD Signature image" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Signature-image.png" alt="GD Signature image GroupDocs Newsletter May 2013: GroupDocs Comparison CMS Integration and GroupDocs Viewer for .NET"  /></a></p>
<ul>
<li>Embedded signature enhancements to support automatically adding fields to positions within documents.</li>
</ul>
<div>
<div><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Dashboard-image.png"><img class="alignnone size-full wp-image-2187" title="GD Dashboard image" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Dashboard-image.png" alt="GD Dashboard image GroupDocs Newsletter May 2013: GroupDocs Comparison CMS Integration and GroupDocs Viewer for .NET"  /></a></div>
<div>
<ul>
<li>New document post-upload progress indicator.</li>
<li>Various optimizations to improve usability.</li>
</ul>
<div>
<div><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-API-image1.png"><img class="alignnone size-full wp-image-2207" title="GD API image" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-API-image1.png" alt="GD API image1 GroupDocs Newsletter May 2013: GroupDocs Comparison CMS Integration and GroupDocs Viewer for .NET"  /></a></div>
<ul>
<li>Support for serving document images directly from <a href="http://groupdocs.com/marketplace/storage" target="_self">Windows Azure, Google Storage and Amazon S3</a>.</li>
<li>File system security enhancements.</li>
</ul>
<div>
<p><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Comparison-Integration-image1.png"><img class="alignnone size-full wp-image-2209" title="GD Comparison Integration image" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Comparison-Integration-image1.png" alt="GD Comparison Integration image1 GroupDocs Newsletter May 2013: GroupDocs Comparison CMS Integration and GroupDocs Viewer for .NET"  /></a></p>
<ul>
<li><a href="https://github.com/groupdocs/moodle-groupdocs-comparison" rel="nofollow">Created GroupDocs Comparison plugin for Moodle 2.x</a></li>
<li><a href="https://github.com/groupdocs/magento-groupdocs-comparison-source" rel="nofollow">Created GroupDocs Comparison plugin for Magento</a></li>
<li><a href="https://github.com/groupdocs/ez-groupdocs-comparison-source" rel="nofollow">Created GroupDocs Comparison plugin for eZ Publish</a></li>
<li><a href="https://github.com/groupdocs/enano-groupdocs-comparison-source" rel="nofollow">Created GroupDocs Comparison plugin for Enano CMS</a></li>
<li><a href="https://github.com/groupdocs/knowledgetree-groupdocs-comparison" rel="nofollow">Created GroupDocs Comparison plugin for KnowledgeTree</a></li>
<li><a href="https://github.com/groupdocs/pligg-groupdocs-comparison-source" rel="nofollow">Created GroupDocs Comparison plugin for Pligg CMS</a></li>
<li><a href="https://github.com/groupdocs/textpattern-groupdocs-comparison-source" rel="nofollow">Created GroupDocs Comparison plugin for TextPattern CMS</a></li>
<li><a href="https://github.com/groupdocs/sugarscrm-groupdocs-comparison-source" rel="nofollow">Created GroupDocs Comparison plugin for SugarCRM</a></li>
<li><a href="https://github.com/groupdocs/getsimple-groupdocs-comparison-source" rel="nofollow">Created GroupDocs Comparison plugin for GetSimple</a></li>
<li><a href="https://github.com/groupdocs/dnn-groupdocs-comparison-source" rel="nofollow">Created GroupDocs Comparison plugin for DNN</a></li>
<li><a href="https://github.com/groupdocs/confluence-groupdocs-comparison-source" rel="nofollow">Created GroupDocs Comparison plugin for Confluence</a></li>
<li><a href="https://github.com/groupdocs/alfresco-groupdocs-comparison-source" rel="nofollow">Created GroupDocs Comparison plugin for Alfresco</a></li>
<li><a href="https://github.com/groupdocs/opencms-groupdocs-comparison-source" rel="nofollow">Created GroupDocs Comparison plugin for OpenCMS</a></li>
<li><a href="https://github.com/groupdocs/jahia-groupdocs-comparison-source" rel="nofollow">Created GroupDocs Comparison plugin for Jahia</a></li>
<li><a href="https://github.com/groupdocs/magnolia-groupdocs-comparison-source" rel="nofollow">Created GroupDocs Comparison plugin for Magnolia</a></li>
<li><a href="https://github.com/groupdocs/pimcore-groupdocs-comparison-source" rel="nofollow">Published GroupDocs Comparison plugin for Pimcore</a></li>
<li><a href="https://github.com/liosha2007/plone-groupdocs-comparison-source" rel="nofollow">Published GroupDocs Comparison plugin for Plone</a></li>
</ul>
<div><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/SDK-API-Sample-Updates.png"><img class="alignnone size-full wp-image-2190" title="SDK API Sample Updates" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/SDK-API-Sample-Updates.png" alt="SDK API Sample Updates GroupDocs Newsletter May 2013: GroupDocs Comparison CMS Integration and GroupDocs Viewer for .NET"  /></a></div>
<div>
<ul>
<li><a href="https://github.com/groupdocs/groupdocs-java" rel="nofollow">Updated Java SDK (Release version 1.4.0)</a></li>
<li><a href="https://github.com/groupdocs/groupdocs-php" rel="nofollow">Updated PHP SDK (Release version 1.4.0)</a></li>
<li><a href="https://github.com/groupdocs/groupdocs-python" rel="nofollow">Updated Python SDK (Release version 1.4.0)</a></li>
<li><a href="https://github.com/groupdocs/groupdocs-python3" rel="nofollow">Updated Python 3 SDK (Release version 1.4.0)</a></li>
<li><a href="https://github.com/groupdocs/groupdocs-salesforce" rel="nofollow">Updated Apex (salesforce) SDK (Release version 1.4.0)</a></li>
<li><a href="https://github.com/groupdocs/groupdocs-apex-samples/" rel="nofollow">Added new samples for SalesForce integrations</a></li>
</ul>
</div>
</div>
</div>
</div>
</div>
<h2><a href="http://groupdocs.com/blog/wp-content/uploads/2013/02/Coming-Soon.png"><img title="Coming Soon" src="http://groupdocs.com/blog/wp-content/uploads/2013/02/Coming-Soon.png" alt="Coming Soon GroupDocs Newsletter May 2013: GroupDocs Comparison CMS Integration and GroupDocs Viewer for .NET"  /></a></h2>
<p>Expect these exciting features soon:</p>
<p><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Viewer-image1.png"><img class="alignnone size-full wp-image-2212" title="GD Viewer image" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Viewer-image1.png" alt="GD Viewer image1 GroupDocs Newsletter May 2013: GroupDocs Comparison CMS Integration and GroupDocs Viewer for .NET"  /></a></p>
<ul>
<li>GroupDocs Viewer for .NET - Install GroupDocs Viewer as part of your platform and .NET apps.</li>
<li>GroupDocs Viewer plugin for FireFox.</li>
<li>GroupDocs Viewer plugin for Google Chrome.</li>
</ul>
<p><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Assembly-image2.png"><img class="alignnone size-full wp-image-2214" title="GD Assembly image" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Assembly-image2.png" alt="GD Assembly image2 GroupDocs Newsletter May 2013: GroupDocs Comparison CMS Integration and GroupDocs Viewer for .NET"  /></a></p>
<ul>
<li>GroupDocs Assembly v2.0 - Support for merging tabular data.</li>
<li>GroupDocs Assembly v2.0 - Enhanced and streamlined UI.</li>
</ul>
<p><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Signature-image1.png"><img class="alignnone size-full wp-image-2215" title="GD Signature image" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Signature-image1.png" alt="GD Signature image1 GroupDocs Newsletter May 2013: GroupDocs Comparison CMS Integration and GroupDocs Viewer for .NET"  /></a></p>
<ul>
<li>GroupDocs Signature v2.0 - New high-fidelity pressure-sensitive signing pad and improved UI.</li>
<li>Publish Signature plugin for Moodle.</li>
<li>Publish Signature plugin for CMSMS.</li>
<li>GroupDocs Signature plugin for Gmail (Chrome).</li>
</ul>
<p><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Comparison-image2.png"><img class="alignnone size-full wp-image-2216" title="GD Comparison image" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/GD-Comparison-image2.png" alt="GD Comparison image2 GroupDocs Newsletter May 2013: GroupDocs Comparison CMS Integration and GroupDocs Viewer for .NET"  /></a></p>
<ul>
<li>GroupDocs Comparison v2.0 - Improved UI.</li>
</ul>
<h2><a href="http://groupdocs.com/blog/wp-content/uploads/2013/02/Featured-Blogpost.png"><img title="Featured Blogpost" src="http://groupdocs.com/blog/wp-content/uploads/2013/02/Featured-Blogpost.png" alt="Featured Blogpost GroupDocs Newsletter May 2013: GroupDocs Comparison CMS Integration and GroupDocs Viewer for .NET"  /></a></h2>
<p>Following are some of the popular blog posts in the month of March:</p>
<ul>
<li><a href="http://groupdocs.com/blog/groupdocs-apps-v2-4-features-and-fixes" rel="nofollow">GroupDocs Apps v2.4 - Features and Fixes</a></li>
<li><a href="http://groupdocs.com/blog/how-to-perform-callbacks-with-groupdocs-php-sdk" rel="nofollow">How to perform Callbacks with GroupDocs PHP SDK</a></li>
<li><a href="http://groupdocs.com/blog/how-to-streamline-your-document-signing-using-online-signature" rel="nofollow">How to Streamline Your Document Signing Using Online Signature?</a></li>
<li><a href="http://groupdocs.com/blog/how-to-compare-files-with-groupdocs-php-sdk" rel="nofollow">How to Compare Files with GroupDocs PHP SDK</a></li>
<li><a href="http://groupdocs.com/blog/how-to-create-groupdocs-plugin-for-cms" rel="nofollow">How to Create GroupDocs Plugin for Contao CMS</a></li>
</ul>
<p>Thank you for choosing GroupDocs.</p>
<p>The GroupDocs Team</p>
]]></content:encoded>
			<wfw:commentRss>http://groupdocs.com/blog/groupdocs-newsletter-may-2013-groupdocs-comparison-cms-integration-and-groupdocs-viewer-for-net/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to merge data fields from a DOCX file with a data source and output to PDF</title>
		<link>http://groupdocs.com/blog/how-to-merge-data-fields-from-a-docx-file-with-a-data-source-and-output-to-pdf</link>
		<comments>http://groupdocs.com/blog/how-to-merge-data-fields-from-a-docx-file-with-a-data-source-and-output-to-pdf#comments</comments>
		<pubDate>Fri, 03 May 2013 12:30:06 +0000</pubDate>
		<dc:creator>Derek</dc:creator>
				<category><![CDATA[Tech Blog]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[document collaboration]]></category>
		<category><![CDATA[document management]]></category>
		<category><![CDATA[online document management system]]></category>
		<category><![CDATA[php api]]></category>

		<guid isPermaLink="false">http://groupdocs.com/blog/?p=2150</guid>
		<description><![CDATA[This article explains how to get the fields from a template DOCX file, fill them with data and merge to new PDF file using GroupDocs. Requirements PHP 5.3 Apache ModRewrite PHP Curl extension PHP Sockets extension (php_sockets.dll) GroupDocs PHP SDK composer.phar (Download from http://getcomposer.org/download/ or use the included version.) FatFree framework (https://github.com/bcosca/fatfree) We already know [...]]]></description>
			<content:encoded><![CDATA[<p>This article explains how to get the fields from a template DOCX file, fill them with data and merge to new PDF file using GroupDocs.</p>
<h2>Requirements</h2>
<ul>
<li>PHP 5.3</li>
<li>Apache ModRewrite</li>
<li>PHP Curl extension</li>
<li>PHP Sockets extension (php_sockets.dll)</li>
<li>GroupDocs PHP SDK</li>
<li>composer.phar (Download from <a href="http://getcomposer.org/download/">http://getcomposer.org/download/</a> or use the included version.)</li>
<li>FatFree framework (<a href="https://github.com/bcosca/fatfree">https://github.com/bcosca/fatfree</a>)</li>
</ul>
<p>We already know how to install the Fatfree framework and prepare for creating the sample from <a href="http://groupdocs.com/blog/tech-blog/archive/2013/03/01/how-to-convert-files-with-groupdocs-php-sdk.html">the previous article</a>. The sample that we create in this article is not much different from other sample with Fatfree. We need a template file with a form and a controller file to process entered data.</p>
<h2>Sample creation</h2>
<p>The template file is the same as in <a href="http://groupdocs.com/blog/tech-blog/archive/2013/03/01/how-to-convert-files-with-groupdocs-php-sdk.html">the previous article</a>. Because of this, I will not explain the template file but just show the code.</p>
<h3>Template file code</h3>
<p></p><pre class="crayon-plain-tag">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
	&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/&gt;
	&lt;title&gt;Powered by {{ @VERSION }}&lt;/title&gt;
	&lt;style type="text/css"&gt;
		{{ Web::minify('templates/',array('style.css'),FALSE) }}
	&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h3 style="text-align:center;"&gt;&lt;a href="/index.php"&gt;GroupDocs PHP SDK Samples&lt;/a&gt; - Merge fields&lt;/h3&gt;

&lt;div class='samplecontent' style="padding:10px;"&gt;
   &lt;span class="description"&gt;&lt;i&gt;This sample will show how to merge data fields in docx file with data source and get result file as PDF file using PHP SDK&lt;/i&gt;&lt;/span&gt; &lt;br/&gt;
    &lt;br /&gt;
   &lt;p&gt;You entered:
   &lt;p&gt;ClientID = {{@userId}}
   &lt;p&gt;PrivateKey = {{@privateKey}}
   &lt;p&gt;File Id = {{@fileId}}

   &lt;p&gt;&lt;font color="red"&gt;{{@error}}&lt;/font&gt;
   &lt;div id="requestForm" style="padding:20px; border:1px solid black;"&gt;
   &lt;p&gt; Enter data for request and press "Make request" button &lt;/p&gt;
        &lt;form action="controller" method = "post" enctype = 'multipart/form-data'&gt;
            &lt;br /&gt;
            &lt;label for='client_id'&gt;GroupDocs Client ID&lt;/label&gt;
            &lt;br /&gt;
            &lt;input type='text' name='client_id' value="{{@userId}}" /&gt;
            &lt;br /&gt;
            &lt;label for='private_key'&gt;GroupDocs PrivateKey&lt;/label&gt;
            &lt;br /&gt;
            &lt;input type='text' name='private_key'  value="{{@privateKey}}" /&gt;
            &lt;br /&gt;
            &lt;br /&gt;
            &lt;input type="radio" name="sourse" value="guid" id="id" onClick="display('guid');" checked&gt;File ID (GUID) &lt;/input&gt;
            &lt;br /&gt;
            &lt;input type="radio" name="sourse" value="local" id="localField" onClick="display('local');" &gt;Upload local file &lt;/input&gt;
            &lt;br /&gt;
            &lt;input type="radio" name="sourse" value="url" id="urlField" onClick="display('url');" &gt;Upload file from URL &lt;/input&gt;
            &lt;br /&gt;

            &lt;label for='private_key' id="guid"&gt;GroupDocs fileID&lt;/label&gt;
            &lt;br /&gt;
            &lt;input type='text' name='fileId' id="guidfield" value="{{@fileId}}" /&gt;

            &lt;label for='file' id="file" style="display:none;"&gt;Local file&lt;/label&gt;
            &lt;br /&gt;
            &lt;input type='file' name='file' id="filefield" style="display:none;" /&gt;

            &lt;label for='private_key' style="display:none;" id="url"&gt;File URL&lt;/label&gt;
            &lt;br /&gt;
            &lt;input type='text' name='url'  value="" id="urlfield" style="display:none;" /&gt;
            &lt;br /&gt;
            &lt;input type='submit' value='Make Request'/&gt;
        &lt;/form&gt;
   &lt;/div&gt;
   &lt;div  style="padding:20px; border:1px solid black;"&gt;
        &lt;font color="green"&gt;{{@message}}&lt;/font&gt;
        &lt;iframe frameborder="0" width="500" height="650" src="{{@url}}"&gt;&lt;/iframe&gt;
   &lt;/div&gt;
   &lt;br/&gt;
&lt;/div&gt;

 &lt;include href="links.htm" /&gt;
&lt;script type="text/javascript"&gt;

    function display(_element_id) {

             if (_element_id == "guid") {
                 var element1 = document.getElementById("file");
                 var element2 = document.getElementById("filefield");
                 var element3 = document.getElementById("url");
                 var element4 = document.getElementById("urlfield");
                 var element5 = document.getElementById("guid");
                 var element6 = document.getElementById("guidfield");
                 element1.style.display = "none";
                 element2.style.display = "none";
                 element3.style.display = "none";
                 element4.style.display = "none";
                 element5.style.display = "inline";
                 element6.style.display = "inline";

             }

             if (_element_id == "local") {
                 var element1 = document.getElementById("file");
                 var element2 = document.getElementById("filefield");
                 var element3 = document.getElementById("url");
                 var element4 = document.getElementById("urlfield");
                 var element5 = document.getElementById("guid");
                 var element6 = document.getElementById("guidfield");
                 element1.style.display = "inline";
                 element2.style.display = "inline";
                 element3.style.display = "none";
                 element4.style.display = "none";
                 element5.style.display = "none";
                 element6.style.display = "none";

             }

             if (_element_id == "url") {
                 var element1 = document.getElementById("url");
                 var element2 = document.getElementById("urlfield");
                 var element3 = document.getElementById("file");
                 var element4 = document.getElementById("filefield");
                 var element5 = document.getElementById("guid");
                 var element6 = document.getElementById("guidfield");
                 element1.style.display = "inline";
                 element2.style.display = "inline";
                 element3.style.display = "none";
                 element4.style.display = "none";
                 element5.style.display = "none";
                 element6.style.display = "none";
             }

         }
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre><p>OK, what's happening with the template file clear so lets take a look at the controller file.</p>
<h3>Controller file</h3>
<p>We already know how to create this file. If you're unsure, look at <a href="http://groupdocs.com/blog/tech-blog/archive/2013/03/01/how-to-convert-files-with-groupdocs-php-sdk.html">a previous post that explains how</a>.</p>
<p>Below, I'll show you the complete controller code and then explain how it works.</p><pre class="crayon-plain-tag">&lt;?php
    //&lt;i&gt;This sample will show how to merge data fields in docx file with data source and get result file as PDF file&lt;/i&gt;

    //###Set variables and get POST data
    F3::set('userId', '');
    F3::set('privateKey', '');
    $clientId = F3::get('POST["client_id"]');
    $privateKey = F3::get('POST["private_key"]');

    function mergeFields($clientId, $privateKey, $basePath)
    {
        //###Check if user entered all parameters
        if (empty($clientId) || empty($privateKey)) {
            throw new Exception('Please enter FILE ID');
        } else {
            F3::set('userId', $clientId);
            F3::set('privateKey', $privateKey);
            //###Create Signer, ApiClient and Storage Api objects

            //Create signer object
            $signer = new GroupDocsRequestSigner($privateKey);
            //Create apiClient object
            $apiClient = new APIClient($signer);
            //Create Doc Api object
            $docApi = new DocApi($apiClient);
            //Create Storage Api object
            $apiStorage = new StorageApi($apiClient);
            //Create AsyncApi object
            $api = new AsyncApi($apiClient);
            $mergApi = new MergeApi($apiClient);
            //Get entered by user data
            $url = F3::get('POST["url"]');
            $file = $_FILES['file'];
            $fileId = f3::get('POST["fileId"]');
            //Check if user choose upload file from URL
            if ($url != "") {
                //Upload file from URL
                $uploadResult = $apiStorage-&gt;UploadWeb($clientId, $url);
                //Check is file uploaded
                if ($uploadResult-&gt;status == "Ok") {
                    //Get file GUID
                    $fileGuId = $uploadResult-&gt;result-&gt;guid;
                    $fileId = "";
                //If it isn't uploaded throw exception to template
                } else {
                    throw new Exception($uploadResult-&gt;error_message);
                }
            }
            //Check is user choose upload local file
            if ($_FILES['file']["name"] != "") {
                //Temp name of the file
                $tmp_name = $file['tmp_name'];
                //Original name of the file
                $name = $file['name'];
                //Creat file stream
                $fs = FileStream::fromFile($tmp_name);
                //###Make a request to Storage API using clientId
                //Upload file to current user storage
                $uploadResult = $apiStorage-&gt;Upload($clientId, $name, 'uploaded', "", $fs);

                //###Check if file uploaded successfully
                if ($uploadResult-&gt;status == "Ok") {
                    //Get file GUID
                    $fileGuId = $uploadResult-&gt;result-&gt;guid;
                    $fileId = "";

                //If it isn't uploaded throw exception to template
                } else {
                    throw new Exception($uploadResult-&gt;error_message);
                }
            }
            //Check is user choose file GUID
            if ($fileId != "") {
                //Get entered by user file GUID
                $fileGuId = $fileId;
            }
            //Get feilds from template
            $fields = $docApi-&gt;GetTemplateFields($clientId, $fileGuId);
            //Check status
            if ($fields-&gt;status == "Ok") {
                //Create new Datasource object
                $dataSource = new Datasource();
                //Create empty array
                $array = array();
                //Loop for fields creataion
                for ($i = 0; $i &lt; count($fields-&gt;result-&gt;fields); $i++) {
                    //Create new DatasourceField object
                    $field = new DatasourceField();
                    //Set DatasourceFiled data
                    $field-&gt;name = $fields-&gt;result-&gt;fields[$i]-&gt;name;
                    $field-&gt;type = "text";
                    $field-&gt;values = array("value1", "value2");
                    //Push DatasourceField to array
                    array_push($array, $field);
                }
                //Set array feilds array to the Datasourc
                $dataSource-&gt;fields = $array;
                //Add Datasource to GroupDocs
                $addDataSource = $mergApi-&gt;AddDataSource($clientId, $dataSource);
                //Check status
                if ($addDataSource-&gt;status == "Ok") {
                    //If status ok merge Datasource to new pdf file
                    $job = $mergApi-&gt;MergeDatasource($clientId, $fileGuId, $addDataSource-&gt;result-&gt;datasource_id, "pdf", null);
                    //Check status
                    if ($job-&gt;status == "Ok") {
                        //### Check job status
                         for ($n = 0; $n &lt;= 5; $n++) {
                             //Delay necessary that the inquiry would manage to be processed
                             sleep(5);
                             //Make request to api for get document info by job id
                             $jobInfo = $api-&gt;GetJobDocuments($clientId, $job-&gt;result-&gt;job_id);
                             //Check job status, if status is Completed or Archived exit from cycle
                             if ($jobInfo-&gt;result-&gt;job_status == "Completed" || $jobInfo-&gt;result-&gt;job_status == "Archived") {
                                 break;
                             //If job status Postponed throw exception with error
                             } elseif ($jobInfo-&gt;result-&gt;job_status == "Postponed") {
                                 throw new Exception("Job is failed");

                             }
                         }
                         //Get file guid
                         $guid = $jobInfo-&gt;result-&gt;inputs[0]-&gt;outputs[0]-&gt;guid;
                          //Get file name
                         $name = $jobInfo-&gt;result-&gt;inputs[0]-&gt;outputs[0]-&gt;name;
                         //Local path to the downloads folder
                         $downloadFolder = dirname(__FILE__). '/../downloads';
                         //Check is folder exist
                         if (!file_exists($downloadFolder)) {
                             //If folder don't exist create it
                             mkdir($downloadFolder);
                         }
                         //Obtaining file stream of downloading file and definition of folder where to download file
                         $outFileStream =  FileStream::fromHttp($downloadFolder, $name);
                         //Download file from GroupDocs.
                         $download = $apiStorage-&gt;GetFile($clientId, $guid, $outFileStream);
                         f3::set("message", "File was converted and downloaded to the " . $downloadFolder . "/" . $name);
                         //### If request was successfull
                         //Generation of iframe URL using $pageImage-&gt;result-&gt;guid
                         $iframe = 'https://apps.groupdocs.com/document-viewer/embed/' . $guid;

                    } else {
                        throw new Exception($job-&gt;error_message);
                    }
                } else {
                    throw new Exception($addDataSource-&gt;error_message);
                }
            } else {
                throw new Exception($fields-&gt;error_message);
            }

            //Set variable with results for template

            return f3::set('url', $iframe);
        }
    }

    try {
        mergeFields($clientId, $privateKey, $basePath);
    } catch(Exception $e) {
        $error = 'ERROR: ' .  $e-&gt;getMessage() . "\n";
        f3::set('error', $error);
    }
    //Process template
    echo Template::serve('template.htm');</pre><p>That's the controller: open your mind and plunge in.</p>
<p>First of all, we get all the data transfered from the form by POST to the controller. This block of code does that:</p><pre class="crayon-plain-tag">//###Set variables and get POST data
    F3::set('userId', '');
    F3::set('privateKey', '');
    $clientId = F3::get('POST["client_id"]');
    $privateKey = F3::get('POST["private_key"]');</pre><p>As you can see, we use the Fatfree method <tt>F3::set</tt> to initially set the template variables and then the <tt>F3::get</tt> method to get the posted data. We have all necessary data to create API objects; the rest of the data we will get later.</p>
<p>Let's create a function that takes this data, checks it and does the rest of the magic. The function is called <tt>mergeFields</tt> and a definition looks like this: <tt>function mergeFields($clientId, $privateKey)</tt>. The <tt>mergeFields</tt> function takes two parameters - client ID and private key. This data is most important because without it, we can't send a request to the API. That's why we check that it's been entered with this code:</p><pre class="crayon-plain-tag">if (empty($clientId) || empty($privateKey)) {
            throw new Exception('Please enter FILE ID');
        } else {
            F3::set('userId', $clientId);
            F3::set('privateKey', $privateKey);</pre><p>Then, if the client ID and private key have been entered we proceed with API objects creation. I expect you already know how to do this.</p>
<p>Next, we check whether the user wants to upload a local file, one from the web, or a file already in the GroupDocs account. We can work with documents through the file GUID. We dont have this data, but that's not a problem - lets get it. Simply use the Fatfree method <tt>F3::get</tt> to get the client ID and private key.</p>
<p>Get the rest of the data:</p><pre class="crayon-plain-tag">//Get entered by user data
            $url = F3::get('POST["url"]');
            $file = $_FILES['file'];
            $fileId = f3::get('POST["fileId"]');</pre><p>Since this data are simple strings - with the exception of $file - check which of them are chosen by elementary verification on an empty string: <tt>if ($url != "") or if ($fileId != "")</tt>.</p>
<p>If you wonder what to do if a user selects to upload a local file, how to check it. It's not a problem. In the global variable which consist of the local file we have an array of file data such as file name, temp name and file content. To check if a user has selected a local file, simply check if the file name is empty. This array field consist of string data and we can check it for empty string: <tt>if ($_FILES['file']["name"] != "")</tt>.</p>
<p>According to which check returns "true", we know whether to use an entered file GUID or upload a file in three different ways. How to do this you can read in last weeks post: <a href="http://groupdocs.com/blog/two-ways-of-uploading-files-into-a-groupdocs-account">Two ways to upload files</a>.</p>
<p>The most interesting part, and culmination of this example, is to get the field from template DOCX file and merge them to a PDF file. To do this, we need this GroupDocs PHP SDK methods:</p>
<ul>
<li> From <tt>DocApi GetTemplateFields</tt></li>
<li>From <tt>MergeApi AddDataSource</tt> and <tt>MergeDatasource</tt></li>
<li>From <tt>AsyncApi GetJobDocuments</tt></li>
<li>And from <tt>StorageApi GetFile</tt></li>
</ul>
<p>First, let's take a look at the code which will do all this work and use our methods:</p><pre class="crayon-plain-tag">//Get fields from template
            $fields = $docApi-&gt;GetTemplateFields($clientId, $fileGuId);
            //Check status
            if ($fields-&gt;status == "Ok") {
                //Create new Datasource object
                $dataSource = new Datasource();
                //Create empty array
                $array = array();
                //Loop for fields creataion
                for ($i = 0; $i &lt; count($fields-&gt;result-&gt;fields); $i++) {
                    //Create new DatasourceField object
                    $field = new DatasourceField();
                    //Set DatasourceFiled data
                    $field-&gt;name = $fields-&gt;result-&gt;fields[$i]-&gt;name;
                    $field-&gt;type = "text";
                    $field-&gt;values = array("value1", "value2");
                    //Push DatasourceField to array
                    array_push($array, $field);
                }
                //Set array feilds array to the Datasourc
                $dataSource-&gt;fields = $array;
                //Add Datasource to GroupDocs
                $addDataSource = $mergApi-&gt;AddDataSource($clientId, $dataSource);
                //Check status
                if ($addDataSource-&gt;status == "Ok") {
                    //If status ok merge Datasource to new pdf file
                    $job = $mergApi-&gt;MergeDatasource($clientId, $fileGuId, $addDataSource-&gt;result-&gt;datasource_id, "pdf", null);
                    //Check status
                    if ($job-&gt;status == "Ok") {
                        //### Check job status
                         for ($n = 0; $n &lt;= 5; $n++) {
                             //Delay necessary that the inquiry would manage to be processed
                             sleep(5);
                             //Make request to api for get document info by job id
                             $jobInfo = $api-&gt;GetJobDocuments($clientId, $job-&gt;result-&gt;job_id);
                             //Check job status, if status is Completed or Archived exit from cycle
                             if ($jobInfo-&gt;result-&gt;job_status == "Completed" || $jobInfo-&gt;result-&gt;job_status == "Archived") {
                                 break;
                             //If job status Postponed throw exception with error
                             } elseif ($jobInfo-&gt;result-&gt;job_status == "Postponed") {
                                 throw new Exception("Job is failed");

                             }
                         }
                         //Get file guid
                         $guid = $jobInfo-&gt;result-&gt;inputs[0]-&gt;outputs[0]-&gt;guid;
                          //Get file name
                         $name = $jobInfo-&gt;result-&gt;inputs[0]-&gt;outputs[0]-&gt;name;
                         //Local path to the downloads folder
                         $downloadFolder = dirname(__FILE__). '/../downloads';
                         //Check is folder exist
                         if (!file_exists($downloadFolder)) {
                             //If folder don't exist create it
                             mkdir($downloadFolder);
                         }
                         //Obtaining file stream of downloading file and definition of folder where to download file
                         $outFileStream =  FileStream::fromHttp($downloadFolder, $name);
                         //Download file from GroupDocs.
                         $download = $apiStorage-&gt;GetFile($clientId, $guid, $outFileStream);</pre><p>The logic is simple.</p>
<ul>
<li>First, we get all the fields from the template DOCX file with the <tt>GetTemplateFields</tt> method. It takes the parameters client ID and template DOCX file GUID. The method returns an object with fields.</li>
<li>Now, create a <tt>DataSource</tt> object in which one of the parameters is a <tt>DataSourceFields</tt> array which we must create. We will put the field we get from template DOCX file into this array. This action occurs in this peace of code:</li>
</ul>
<p></p><pre class="crayon-plain-tag">//Create empty array
                $array = array();
                //Loop for fields creataion
                for ($i = 0; $i &lt; count($fields-&gt;result-&gt;fields); $i++) {
                    //Create new DatasourceField object
                    $field = new DatasourceField();
                    //Set DatasourceFiled data
                    $field-&gt;name = $fields-&gt;result-&gt;fields[$i]-&gt;name;
                    $field-&gt;type = "text";
                    $field-&gt;values = array("value1", "value2");
                    //Push DatasourceField to array
                    array_push($array, $field);
                }
                //Set array feilds array to the Datasourc
                $dataSource-&gt;fields = $array;</pre><p>As you can see, the <tt>DataSourceFields</tt> object has a values parameter. Into this parameter we put an array of strings or only string which will be added to the field as content.</p>
<ul>
<li>After creating the DataSource object, the next step is to add DataSource to GroupDocs for the convertion to PDF. This trick can be done as follows:</li>
</ul>
<p></p><pre class="crayon-plain-tag">//Add Datasource to GroupDocs
                $addDataSource = $mergApi-&gt;AddDataSource($clientId, $dataSource);</pre><p>In response to this we get the <strong>datasource ID</strong> by which we can both merge it and convert to PDF, thus killing two birds with one stone.</p>
<ul>
<li> Take the client ID, datasource ID, the original DOCX file GUID and put all of this into the <tt>MergeDatasource</tt> method. This request in code:</li>
</ul>
<p></p><pre class="crayon-plain-tag">$job = $mergApi-&gt;MergeDatasource($clientId, $fileGuId, $addDataSource-&gt;result-&gt;datasource_id, "pdf", null);</pre><p>As you see, one of the input parameters is a string with type of the result file. When the API gets this request, it creates a new PDF file with merged fields.</p>
<p>Phew, we merged our fields to a new PDF file and now we can download it and see it in an iframe. The <tt>MergeDatasource</tt> method returns Job id using which in the <tt>GetJobDocuments</tt> method we get all the info about the new PDF file that we need, such is GUID and name.</p>
<ul>
<li>To download it, create a FileStream which contains a local path for downloading the file:</li>
</ul>
<p></p><pre class="crayon-plain-tag">//Obtaining file stream of downloading file and definition of folder where to download file
                         $outFileStream =  FileStream::fromHttp($downloadFolder, $name);</pre><p>After that use the <tt>GetFile</tt> method to download it: <tt>$download = $apiStorage-&gt;GetFile($clientId, $guid, $outFileStream);<tt></tt></tt></p>
<p>You already know how to generate an iframe.</p>
<p>The only thing left is to call our function and return the new PDF file GUID to the template to show in the browser as an iframe. You already know how to do this too, if you've followed this article series.</p>
<p>And we're done!</p>
<h2>Screenshots</h2>
<p>Here are two screenshots that show the input form and the output file so you can see the process in action.</p>
<h4>The input form</h4>
<p><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/form.png"><img class="alignleft  wp-image-2151" title="The input form" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/form.png" alt="form How to merge data fields from a DOCX file with a data source and output to PDF"  /></a></p>
<h4>The output PDF</h4>
<p><a href="http://groupdocs.com/blog/wp-content/uploads/2013/05/iframe.png"><img class="alignleft size-full wp-image-2152" title="The iframe with the output PDF" src="http://groupdocs.com/blog/wp-content/uploads/2013/05/iframe.png" alt="iframe How to merge data fields from a DOCX file with a data source and output to PDF"  /></a></p>
]]></content:encoded>
			<wfw:commentRss>http://groupdocs.com/blog/how-to-merge-data-fields-from-a-docx-file-with-a-data-source-and-output-to-pdf/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Two ways of uploading files into a GroupDocs account</title>
		<link>http://groupdocs.com/blog/two-ways-of-uploading-files-into-a-groupdocs-account</link>
		<comments>http://groupdocs.com/blog/two-ways-of-uploading-files-into-a-groupdocs-account#comments</comments>
		<pubDate>Mon, 29 Apr 2013 16:02:14 +0000</pubDate>
		<dc:creator>Derek</dc:creator>
				<category><![CDATA[Tech Blog]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[document collaboration]]></category>
		<category><![CDATA[document management]]></category>
		<category><![CDATA[online document management system]]></category>
		<category><![CDATA[php api]]></category>

		<guid isPermaLink="false">http://groupdocs.com/blog/?p=2092</guid>
		<description><![CDATA[Working with GroupDocs SDK we usually need a GUID to work with a document. But it's not very comfortable for users to work with GUIDs. So in your app, you can use two methods to upload a file to a GroupDocs account and get it's GUID programmatically. Requirements PHP 5.3 Apache ModRewrite PHP Curl extension [...]]]></description>
			<content:encoded><![CDATA[<p>Working with GroupDocs SDK we usually need a GUID to work with a document. But it's not very comfortable for users to work with GUIDs. So in your app, you can use two methods to upload a file to a GroupDocs account and get it's GUID programmatically.</p>
<h2>Requirements</h2>
<ul>
<li>PHP 5.3</li>
<li>Apache ModRewrite</li>
<li>PHP Curl extension</li>
<li>PHP Sockets extension (php_sockets.dll)</li>
<li><a href="https://github.com/groupdocs/groupdocs-php">GroupDocs PHP SDK</a></li>
<li>composer.phar (Download from <a href="http://getcomposer.org/download/">http://getcomposer.org/download/</a> or use the included version.)</li>
<li>FatFree framework (<a href="https://github.com/bcosca/fatfree">https://github.com/bcosca/fatfree</a>)</li>
</ul>
<p>We already know how to install the Fatfree framework and prepare for creating the sample from <a href="http://groupdocs.com/blog/tech-blog/archive/2013/03/01/how-to-convert-files-with-groupdocs-php-sdk.html">the previous article</a>. So lets start with the magic.</p>
<h2>Theory</h2>
<h3>Upload local file</h3>
<p>To upload a local file we need an actual file. You can view many types to word processing documents (DOC, DOCX, TXT, RTF, ODT), presentations (PPT, PPTX), spreadsheets (XLS, XLSX), portable files (PDF), and image files (JPG, BMP, GIF, TIFF).</p>
<p>From GroupDocs PHP SDK we will need the following methods:</p>
<ul>
<li><tt>Upload</tt></li>
<li><tt>FileStream::fromFile</tt></li>
</ul>
<p>The template is simply an HTML form of the "multipart/form-data" type. This form sends date entered by the user (the client ID, private key and local file data) to the controller. The controller, in turn, gets the data, prepares it for an API request, makes the API request and receives the upload results from the API with info about the uploaded file.</p>
<h3>Upload file from web</h3>
<p>If you think this is going to be complicated, I have to disappoint you. With GroupDocs PHP SDK it's really simple than upload a local file.</p>
<p>To upload a file from the web, we need a direct link to the file. Everything else is the same as when uploading a local file, with the exception of the <tt>upload</tt> method. To do this trick we need only one method: <tt>uploadWeb</tt>. The logic of web uploading is the same as for local file upload.</p>
<p>Since the logic is the same we'll use same template and controller.</p>
<h2>Practice</h2>
<p>As before, create a template file in the <strong>template </strong>folder and a controller file in the <strong>inc_samples</strong> folder.</p>
<h3>Template file code</h3>
<p></p><pre class="crayon-plain-tag">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
	&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/&gt;
	&lt;title&gt;Upload&lt;/title&gt;
	&lt;style type="text/css"&gt;
		{{ Web::minify('templates/',array('style.css'),FALSE) }}
	&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h3 style="text-align:center;"&gt;&lt;a href="/index.php"&gt;GroupDocs PHP SDK Samples&lt;/a&gt; - Upload&lt;/h3&gt;

&lt;div class='samplecontent' style="padding:10px;"&gt;
   &lt;span class="description"&gt;&lt;i&gt;This sample will show how to upload file to GroupDocs using PHP SDK&lt;/i&gt;&lt;/span&gt; &lt;br/&gt;
    &lt;br /&gt;

   &lt;br/&gt;&lt;p&gt;You entered:
   &lt;p&gt;ClientID = {{@userId}}
   &lt;p&gt;PrivateKey = {{@privateKey}}
   &lt;p&gt;&lt;font color="red"&gt;{{@error}}&lt;/font&gt;
   &lt;div id="requestForm" style="padding:20px; border:1px solid black;"&gt;

   &lt;form action="controller" method = "post" enctype = 'multipart/form-data'&gt;
       &lt;label for='client_id'&gt;GroupDocs ClientID&lt;/label&gt;
       &lt;br /&gt;
       &lt;input type='text' name='client_id' value="{{@userId}}" /&gt;
       &lt;br /&gt;
       &lt;label for='private_key'&gt;GroupDocs PrivateKey&lt;/label&gt;
       &lt;br /&gt;
       &lt;input type='text' name='private_key'  value="{{@privateKey}}" /&gt;
       &lt;br /&gt;
       &lt;input type="radio" name="sourse" value="local" id="localField" onClick="display('local');" &gt;Upload local file &lt;/input&gt;
       &lt;br /&gt;
       &lt;input type="radio" name="sourse" value="url" id="urlField" onClick="display('url');" &gt;Upload file from URL &lt;/input&gt;
       &lt;br /&gt;

       &lt;label for='private_key' style="display:none;" id="url"&gt;Upload file from URL&lt;/label&gt;
        &lt;br /&gt;
        &lt;input type='text' name='url'  value="" id="urlfield" style="display:none;" /&gt;

        &lt;label for='file' id="file" style="display:none;"&gt;Upload local file&lt;/label&gt;
        &lt;br /&gt;
        &lt;input type='file' name='file' id="filefield" style="display:none;" /&gt;
        &lt;br /&gt;
       &lt;label for='private_key'&gt;Folder in which you want to copy file&lt;/label&gt;
       &lt;br /&gt;
       &lt;input type='text' name='destPath'  value="{{@folder}}" /&gt;
       &lt;br /&gt;
       &lt;input type='submit' value='Make Request'/&gt;
   &lt;/form&gt;
   &lt;/div&gt;
   &lt;h4&gt;&lt;font color="green"&gt;{{@message}}&lt;/font&gt;&lt;/h4&gt;
   &lt;br/&gt;
 &lt;/div&gt;

 &lt;include href="links.htm" /&gt;
 &lt;script type="text/javascript"&gt;
    function display(_element_id) {

             if (_element_id == "local") {
                 var element1 = document.getElementById("file");
                 var element2 = document.getElementById("filefield");
                 var element3 = document.getElementById("url");
                 var element4 = document.getElementById("urlfield");
                 element1.style.display = "inline";
                 element2.style.display = "inline";
                 element3.style.display = "none";
                 element4.style.display = "none";

             }

             if (_element_id == "url") {
                 var element1 = document.getElementById("url");
                 var element2 = document.getElementById("urlfield");
                 var element3 = document.getElementById("file");
                 var element4 = document.getElementById("filefield");
                 element1.style.display = "inline";
                 element2.style.display = "inline";
                 element3.style.display = "none";
                 element4.style.display = "none";

             }

         }
&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre><p>Let's investigate this code. This is a simple HTML document with JavaScript. To select the file source (local or web) we've added a switch:</p><pre class="crayon-plain-tag">&lt;input type="radio" name="sourse" value="local" id="localField" onClick="display('local');" &gt;Upload local file &lt;/input&gt;</pre><p>This switch calls the JavaScript function display. This function receives one parameter which specifies the source of the file: local or web. Where <tt>local</tt> = upload local file and <tt>url</tt> = upload file from web. Toggling the switch displays the corresponding input field.</p>
<p>OK, it's clear how the template works - it's simple enough. Let's take a look at the <strong>controller</strong>.</p>
<h3>Controller code</h3>
<p></p><pre class="crayon-plain-tag">//###Set variables and get POST data
    F3::set('userId', '');
    F3::set('privateKey', '');
    $clientId = F3::get('POST["client_id"]');
    $privateKey = F3::get('POST["private_key"]');
    $width = f3::get('POST["width"]');
    $height = f3::get('POST["height"]');

    function upload($clientId, $privateKey, $width='400', $height='650')
    {
        //###Check fileGuId
        if (empty($clientId) || empty($privateKey)) {
            throw new Exception('Please enter all required parameters');
        } else {
            F3::set('userId', $clientId);
            F3::set('privateKey', $privateKey);
            //Get base path
            $basePath = f3::get('POST["server_type"]');
            //Get entered by user data
            $fileGuId = "";
            $url = F3::get('POST["url"]');
            $file = $_FILES['file'];
            //###Create Signer, ApiClient and Storage Api objects

            //Create signer object
            $signer = new GroupDocsRequestSigner($privateKey);
            //Create apiClient object
            $apiClient = new APIClient($signer);
            //Create Storage Api object
            $api = new StorageApi($apiClient);
            //Check if user choose upload file from URL
            if ($url != "") {
                //Upload file from URL
                $uploadResult = $api-&gt;UploadWeb($clientId, $url);
                //Check is file uploaded
                if ($uploadResult-&gt;status == "Ok") {
                    //Get file GUID
                    $fileGuId = $uploadResult-&gt;result-&gt;guid;

                //If it isn't uploaded throw exception to template
                } else {
                    throw new Exception($uploadResult-&gt;error_message);
                }
            }
            //Check is user choose upload local file
            if ($_FILES['file']["name"] != "") {
                //Temp name of the file
                $tmp_name = $file['tmp_name'];
                //Original name of the file
                $name = $file['name'];
                //Creat file stream
                $fs = FileStream::fromFile($tmp_name);
                //###Make a request to Storage API using clientId
                //Upload file to current user storage
                $uploadResult = $api-&gt;Upload($clientId, $name, 'uploaded', "", $fs);

                //###Check if file uploaded successfully
                if ($uploadResult-&gt;status == "Ok") {
                    //Get file GUID
                    $fileGuId = $uploadResult-&gt;result-&gt;guid;

                //If it isn't uploaded throw exception to template
                } else {
                    throw new Exception($uploadResult-&gt;error_message);
                }
            }
            //Generation of iframe URL using fileGuId
            $iframe = 'http://apps.groupdocs.com/document-viewer/embed/' . $fileGuId . '?frameborder="0" width=' . $width . 'height=' . $height;
            //If request was successfull - set url variable for template
            f3::set('fileId', $fileGuId);
            return f3::set('url', $iframe);
        }
    }

    try {
        upload($clientId, $privateKey, $width, $height);
    } catch(Exception $e) {
        $error = 'ERROR: ' .  $e-&gt;getMessage() . "\n";
        f3::set('error', $error);
    }
    //Process template
    F3::set('userId', $clientId);
    F3::set('privateKey', $privateKey);
    F3::set('width', $width);
    F3::set('height', $height);

    echo Template::serve('template.htm');</pre><p>Now let's analyze the blocks of code we have here.</p><pre class="crayon-plain-tag">F3::set('userId', '');
    F3::set('privateKey', '');
    $clientId = F3::get('POST["client_id"]');
    $privateKey = F3::get('POST["private_key"]');
    $width = f3::get('POST["width"]');
    $height = f3::get('POST["height"]');</pre><p>In this block we get the data from the form transfered by the POST method with the Fatfree method <tt>F3::get</tt> which gives access to the global arrays such as POST, GET, FILE and SERVER. When we have collected the entered data, we can create a function which will do the job and we will have the ability to check every steps and get errors if there are any. Our function will get four parameters: client ID, private key, width and height (we need width and height for the iframe that will show the uploaded file).</p><pre class="crayon-plain-tag">function upload($clientId, $privateKey, $width='400', $height='650')</pre><p>First of all, we must check whether the client ID and private key are entered. Without this data we can't do anything. Check it with this code:</p><pre class="crayon-plain-tag">if (empty($clientId) || empty($privateKey)) {
            throw new Exception('Please enter all required parameters');</pre><p>If we have this data, we can proceed to the next code block:</p><pre class="crayon-plain-tag">F3::set('userId', $clientId);
F3::set('privateKey', $privateKey)
//Get base path
$basePath = f3::get('POST["server_type"]');
//Get entered by user data
$fileGuId = "";
$url = F3::get('POST["url"]');
$file = $_FILES['file'];
//###Create Signer, ApiClient and Storage Api objects</pre><p>Here we set user data for template and get the rest of the entered data from the form, such as the URL of a web file and the location of the local file. Later, we will check which fields are chosen by this data. Now we must create objects which will set up the relationships with the GroupDocs API and user account. This code does that:</p><pre class="crayon-plain-tag">//Create signer object
 $signer = new GroupDocsRequestSigner($privateKey);
 //Create apiClient object
 $apiClient = new APIClient($signer);
 //Create Storage Api object
 $api = new StorageApi($apiClient);</pre><p>So we can check from where we're about to upload the file and then upload it. To check if the user choose to upload a file from the web, and to upload the file, use this code:</p><pre class="crayon-plain-tag">//Check if user choose upload file from URL
            if ($url != "") {
                //Upload file from URL
                $uploadResult = $api-&gt;UploadWeb($clientId, $url);
                //Check is file uploaded
                if ($uploadResult-&gt;status == "Ok") {
                    //Get file GUID
                    $fileGuId = $uploadResult-&gt;result-&gt;guid;

                //If it isn't uploaded throw exception to template
                } else {
                    throw new Exception($uploadResult-&gt;error_message);
                }
            }</pre><p>This block does all the magic uploading a file from the web. As you can see we check whether <tt>$url</tt> is an empty string. If it is not empty, the user has selected to upload a file from the web and we use the URL. To upload the file, we make a request to the <tt>UploadWeb</tt> method with the client ID and the URL for the file:</p><pre class="crayon-plain-tag">$uploadResult = $api-&gt;UploadWeb($clientId, $url);</pre><p>Thats all for web uploading. Simple, yes?</p>
<p>OK in response to this method we have an object with an array of all the info for this file such as the GUID, name, type and so on. To show this file in an iframe, we only need the GUID. We can get GUID easily:</p><pre class="crayon-plain-tag">$fileGuId = $uploadResult-&gt;result-&gt;guid;</pre><p>If <tt>uploadWeb</tt> fails we get an error message:</p><pre class="crayon-plain-tag">$uploadResult-&gt;error_message</pre><p>But what if the user wants to upload a local file? We can check if they do, and if so upload the local file with this code:</p><pre class="crayon-plain-tag">//Check is user choose upload local file
            if ($_FILES['file']["name"] != "") {
                //Temp name of the file
                $tmp_name = $file['tmp_name'];
                //Original name of the file
                $name = $file['name'];
                //Creat file stream
                $fs = FileStream::fromFile($tmp_name);
                //###Make a request to Storage API using clientId
                //Upload file to current user storage
                $uploadResult = $api-&gt;Upload($clientId, $name, 'uploaded', "", $fs);

                //###Check if file uploaded successfully
                if ($uploadResult-&gt;status == "Ok") {
                    //Get file GUID
                    $fileGuId = $uploadResult-&gt;result-&gt;guid;

                //If it isn't uploaded throw exception to template
                } else {
                    throw new Exception($uploadResult-&gt;error_message);
                }
            }</pre><p>To upload a local file we must get its name, assign it a temporary name and convert it to a FileStream. The first two we can get as usual for multipart/form-data:</p><pre class="crayon-plain-tag">//Temp name of the file
                $tmp_name = $file['tmp_name'];
                //Original name of the file
                $name = $file['name'];</pre><p>And to convert the file to FileStream in the GroupDocs PHP SDK we have very cool thing: <tt>FileStream::fromFile</tt>. This function gets the file's temp name and returns a FileStream. Now we can send request to the GroupDocs API to upload the local file. The <tt>Upload</tt> file method get such parameters as client ID, local file name, description(string), callback URL (in this sample we'll use an empty string but if you want to, you can specify it) and FileStream. In the response object for the <tt>UploadWeb</tt> method we get info about the uploaded file. If the request failed, we get an error message.</p>
<h3>Displaying the file</h3>
<p>We've finished the upload and now we have only to generate an iframe and call our function.</p>
<p>&nbsp;</p><pre class="crayon-plain-tag">//Generation of iframe URL using fileGuId
            $iframe = 'http://apps.groupdocs.com/document-viewer/embed/' . $fileGuId . '?frameborder="0" width=' . $width . 'height=' . $height;
            //If request was successfull - set url variable for template
            f3::set('fileId', $fileGuId);
            return f3::set('url', $iframe);
        }
    }

    try {
        upload($clientId, $privateKey, $width, $height);
    } catch(Exception $e) {
        $error = 'ERROR: ' .  $e-&gt;getMessage() . "\n";
        f3::set('error', $error);
    }
    //Process template
    F3::set('userId', $clientId);
    F3::set('privateKey', $privateKey);
    F3::set('width', $width);
    F3::set('height', $height);

    echo Template::serve('template.htm');</pre><p></p>
<h2>The code in action</h2>
<p>Thats all. Below are a couple of screenshots that show how it looks in action.</p>
<h4>The input form</h4>
<p><a href="http://groupdocs.com/blog/wp-content/uploads/2013/04/form1.png"><img class="size-full wp-image-2093 alignleft" title="The input form" src="http://groupdocs.com/blog/wp-content/uploads/2013/04/form1.png" alt="form1 Two ways of uploading files into a GroupDocs account" width="600" height="345" /></a></p>
<p>&nbsp;</p>
<h4>The iframe showing the uploaded document</h4>
<p><a href="http://groupdocs.com/blog/wp-content/uploads/2013/04/iframe2.png"><img class="size-full wp-image-2094 alignleft" title="The iframe displaying the uploaded file." src="http://groupdocs.com/blog/wp-content/uploads/2013/04/iframe2.png" alt="iframe2 Two ways of uploading files into a GroupDocs account" width="600" height="431" /></a></p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://groupdocs.com/blog/two-ways-of-uploading-files-into-a-groupdocs-account/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>GroupDocs Apps v2.4 &#8211; Features and Fixes</title>
		<link>http://groupdocs.com/blog/groupdocs-apps-v2-4-features-and-fixes</link>
		<comments>http://groupdocs.com/blog/groupdocs-apps-v2-4-features-and-fixes#comments</comments>
		<pubDate>Fri, 19 Apr 2013 13:34:04 +0000</pubDate>
		<dc:creator>Derek</dc:creator>
				<category><![CDATA[Release Notes]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[document collaboration]]></category>
		<category><![CDATA[document management]]></category>
		<category><![CDATA[document upload]]></category>
		<category><![CDATA[GroupDocs Annotate]]></category>
		<category><![CDATA[GroupDocs Signature]]></category>
		<category><![CDATA[GroupDocs Viewer]]></category>
		<category><![CDATA[GroupDocs Viewer Plugin]]></category>
		<category><![CDATA[online document management system]]></category>
		<category><![CDATA[online document viewer]]></category>
		<category><![CDATA[View documents online]]></category>

		<guid isPermaLink="false">http://groupdocs.com/blog/?p=2017</guid>
		<description><![CDATA[We’ve implemented a few new features as well as fixed some major &#38; minor bugs lately. Let’s have a detailed look: GroupDocs Annotation GroupDocs Annotation is an online document annotation app that lets you easily annotate documents and perform document collaboration simply using your browser. Using GroupDocs’ efficient document annotation app, you can annotate and [...]]]></description>
			<content:encoded><![CDATA[<p>We’ve implemented a few new features as well as fixed some major &amp; minor bugs lately. Let’s have a detailed look:</p>
<h2>GroupDocs Annotation</h2>
<p><strong><a href="http://groupdocs.com/apps/annotation">GroupDocs Annotation</a></strong> is an online document annotation app that lets you easily annotate documents and perform document collaboration simply using your browser. Using GroupDocs’ <strong><a href="http://groupdocs.com/apps/annotation/features">efficient document annotation app</a></strong>, you can annotate and collaborate on Word, PDF, or Excel documents, just to name a few.</p>
<p><strong>Features Implemented</strong></p>
<ul>
<li>Major</li>
<ul>
<li>[ANNOTATION-232] Broadcast of horizontal scroll, broadcast of window size percentage when scaling, and support for master and slaves in real-time mode.</li>
</ul>
</ul>
<p><strong>Bugs fixed</strong></p>
<ul>
<li>Critical:</li>
<ul>
<li>[ANNOTATION-220] If a user is registered as a reviewer for multiple documents, he will receive all broadcasted operations into each open document.</li>
<li>[ANNOTATION-226] Export "Normal" raises an error.</li>
<li>[ANNOTATION-230] Downloading an annotated document by using a direct file link fails.</li>
</ul>
</ul>
<ul>
<li>Major:</li>
<ul>
<li>[ANNOTATION-225] The background color of the pages and thumbnails is transparent, which creates flashes when they are being loaded.</li>
<li>[ANNOTATION-228] Annotation v.2. The document should expand when the RHS toolbar is collapsed.</li>
<li>[ANNOTATION-223] Annotation v.2. An iPhone-styled button for switching between broadcast and screen drag, disable pinch to shrink and pullout to magnify, and a setting for removing the toolbar completely.</li>
<li>[ANNOTATION-222] Annotation 2. Search doesn't find the searched text.</li>
</ul>
</ul>
<ul>
<li>Minor</li>
<ul>
<li>[ANNOTATION-224] Text selection is shifted 1 pixel to the right and 1-2 pixels up from the correct position.</li>
<li>[ANNOTATION-227] The "standard header is always shown" option.</li>
</ul>
</ul>
<h2>GroupDocs Viewer</h2>
<p><strong><a href="http://groupdocs.com/apps/viewer">GroupDocs Viewer</a></strong> is an efficient online document viewer that lets you <strong><a href="http://groupdocs.com/apps/viewer/features">view documents online</a></strong> simply using a browser. Since GroupDocs Viewer supports all common and business file formats, it can be used as a PDF viewer, Word viewer, Excel viewer, amongst many others.</p>
<p><strong>Features Implemented</strong></p>
<ul>
<li>Major</li>
<ul>
<li>[WEB-346] Client side code for the installable Viewer.</li>
<li>[WEB-347] JavaScript-based NavigationWidget.</li>
<li>[WEB-348] JavaScript-based ZoomingWidget.</li>
<li>[WEB-351] Installable Viewer: JS document viewer adapter without user ID / private key dependencies, working when some widgets are disabled.</li>
</ul>
<li>Minor
<ul>
<li>[WEB-342] Update document viewer 1.0 header.</li>
<li>[WEB-352] The PortalService for the installable Viewer.</li>
</ul>
</li>
</ul>
<p><strong>Bugs fixed</strong></p>
<ul>
<li>Minor</li>
<ul>
<li>[WEB-343] Document print doesn't work in the embedded viewer.</li>
</ul>
</ul>
<h2><strong>GroupDocs Assembly</strong></h2>
<p><strong><a href="http://groupdocs.com/apps/assembly">GroupDocs Assembly</a></strong> is an efficient document automation and document assembly app that lets you perform document assembly in a jiffy. With GroupDocs Assembly, you can prepare a document for document assembly by adding questionnaires to it and then send out this document to collect responses. Your customers can then add answers to the questionnaires and perform document assembly easily. <strong><a href="http://groupdocs.com/apps/assembly/features">Document automation and document assembly</a></strong> using GroupDocs Assembly lets you save your time and effort.</p>
<p><strong>Features Implemented</strong></p>
<ul>
<li>Major</li>
<ul>
<li>[DA-144] WYSIWYG support for questionnaire answers.</li>
<li>[DA-148] Web hook for the document assembly job.</li>
</ul>
</ul>
<p><strong>Bugs fixed</strong></p>
<ul>
<li>Major:</li>
<ul>
<li>[DA-145] Long questions and answers word-wrap.</li>
</ul>
</ul>
<h2><strong>GroupDocs Signature</strong></h2>
<p><strong><a href="http://groupdocs.com/apps/signature">GroupDocs Signature</a></strong> is an efficient digital signature service, which is completely web-based. GroupDocs' easy-to-use <strong><a href="http://groupdocs.com/apps/signature/features">digital signature service</a></strong> lets you collect digital signatures with no administrative overhead of printing, envelope stuffing and posting.</p>
<p><strong>Features Implemented</strong></p>
<ul>
<li>[SIGN-967] - Signature2: Signed view for envelopes.</li>
<li>[SIGN-968] - Signature 2: Signed embedded view for envelopes.</li>
</ul>
<p><strong>Improvements</strong></p>
<ul>
<li>[SIGN-942] - Signature 2: New status icons for envelopes and forms.</li>
<li>[SIGN-949] - Implement async signing of the signature envelopes.</li>
<li>[SIGN-950] - Adopt signed screen and signed embedded screen to work with async envelope signing process.</li>
<li>[SIGN-956] - Signature 2: Implement envelope-embed signing.</li>
<li>[SIGN-957] - Signature 2: Improve the user experience after clicking "New Envelope" in the envelopes dashboard.</li>
<li>[SIGN-961] - Signature 2: Improve the user experience after clicking "New Form" in the forms dashboard.</li>
<li>[SIGN-980] - Implement changes in <em>envelope.create</em> and <em>envelope.modify</em></li>
<li>[SIGN-981] - New settings while preparing envelope in signature 1 and signature 2.</li>
<li>[SIGN-983] - Signature 2: Implement embed signed screen.</li>
<li>[SIGN-995] - Implement create envelope from envelope in signature 1 and signature 2.</li>
<li>[SIGN-999] - Increase recipient name's length for envelopes.</li>
<li>[SIGN-1005] - Default value for "Include embed link .." settings for envelope should be true.</li>
<li>[SIGN-940] - Signature 2: Implement template preparation wizard.</li>
<li>[SIGN-969] - Signature 2: Forms: recheck that the forms signing is working and apply fixes if not.</li>
<li>[SIGN-998] - Display error messages in embedded signature as a popup.</li>
<li>[SIGN-1014] - Signatrure 1: From archived envelopes, the user should be able to copy the envelope and start over.</li>
<li>[SIGN-1015] - Signature 1: Ensure that recipients with role CC are not included in the recipients' dropdown list in fields preparation.</li>
<li>[SIGN-1016] - Signature 1: For CC recipients, show the embed link button in envelopes dashboard only when envelope is completed.</li>
<li>[SIGN-1018] - Signature 1: Do not show embed link button in envelopes dash board for envelopes with status expired and draft.</li>
<li>[SIGN-1019] - Signature 1: In forms dashboard, add Publish Form in the context menu for draft forms.</li>
<li>[SIGN-1027] - Signature 2: Envelopes: Do not show fields summary on step 6 in envelope preparation wizard.</li>
</ul>
<p><strong>Bugs fixed</strong></p>
<ul>
<li>[SIGN-853] When envelope is signed from the embeddable view, the notification to callback url is not sent.</li>
<li>[SIGN-919] - Demo performance.</li>
<li>[SIGN-927] - Signature 2: Envelopes dashboard, and statuses overlaps the envelope name.</li>
<li>[SIGN-935] - Forms: Form preparation wizard, fields settings: remove all jquery selectors.</li>
<li>[SIGN-944] - Signature 2: Envelopes dashboard, the paging on scrolling does not work properly.</li>
<li>[SIGN-945] - Fix <em>template.recipient.add</em> and <em>template.recipient</em> api methods response.</li>
<li>[SIGN-946] - Sign embed requires login.</li>
<li>[SIGN-947] - Demo signature on send envelope shows error message.</li>
<li>[SIGN-951] - Create public API method to retrieve envelope details.</li>
<li>[SIGN-952] - Fix the signatureEnvelopeDetails widget to use public API method if the viewing mode is public.</li>
<li>[SIGN-953] - Clear the signed document thumbnails, so the most recent pages to be shown in the viewer.</li>
<li>[SIGN-954] - Signature 2: In the sign envelope screen, in the signature creation popup, the font for written signature are not initialized correctly.</li>
<li>[SIGN-955] - Signature 2: If we close the signature popup with ESC key, it can't be shown anymore.</li>
<li>[SIGN-962] - Signature 2: If archived forms list is empty, the select all checkbox is selected.</li>
<li>[SIGN-963] - AddContactIntegration raises error.</li>
<li>[SIGN-964] - Add drop-down field doesn't set acceptableValues and defaultValue.</li>
<li>[SIGN-966] - Inconsistency in signature API boolean parameters.</li>
<li>[SIGN-970] - Comparing word files with revisions information in them is failing.</li>
<li>[SIGN-971] - Cannot add two files with the same name, but different extension to envelope.</li>
<li>[SIGN-972] - If there is drop-down field without list with values, the envelope should not be able to be send.</li>
<li>[SIGN-973] - If there is a drop-down field without list with values, the form should not be able to be published</li>
<li>[SIGN-974] - Drop-down value is reset to the default value on reload even if there is already-set user's value.</li>
<li>[SIGN-975] - If envelope is with status completed, the URL in embed popup should lead to signed envelope.</li>
<li>[SIGN-976] - Signature 1: Incorrect behavior of tab key in signing screen.</li>
<li>[SIGN-978] - Signature 2: Ensure that if error is returned from the web service, the corresponded error message will be displayed.</li>
<li>[SIGN-979] - Extend audit logging to log send and sign events.</li>
<li>[SIGN-982] - Cleanup code in the signature 1 and signature 2 controllers.</li>
<li>[SIGN-984] - Forms: Incorrect document displayed after signing.</li>
<li>[SIGN-985] - Incorrect full name calculation.</li>
<li>[SIGN-986] - CreateSignatureTemplate multiple issues.</li>
<li>[SIGN-987] - AddSignatureTemplateRecipient returns null in template identifier.</li>
<li>[SIGN-988] - Signature 1: Broken layout in templates dashboard if there are no any templates.</li>
<li>[SIGN-989] - DeleteSignatureTemplateDocument raises error.</li>
<li>[SIGN-990] - Upload file in create template wizard fails.</li>
<li>[SIGN-991] - Signature 2: After confirm signing, the user is redirected to login screen if not logged in before.</li>
<li>[SIGN-992] - After the envelope is sent, the owner is included as signer even if it was not set as signer while preparing the nvelope.</li>
<li>[SIGN-993] - UpdateSignatureFormFromTemplate raises error.</li>
<li>[SIGN-994] - Typo in signature envelope API methods.</li>
<li>[SIGN-996] - The final email notification for signed envelope is not send at all.</li>
<li>[SIGN-997] - The owner of the envelope could not see the signed documents if he is not in the signers list.</li>
<li>[SIGN-1000] - Embed signature is not working in IE8.</li>
<li>[SIGN-1001] - Document viewer in signature 2 throws javascript error.</li>
<li>[SIGN-1002] - After envelope deletion, files associated with the envelope are staying.</li>
<li>[SIGN-1003] - After template deletion, files associated with the template are staying.</li>
<li>[SIGN-1004] - After form deletion, files associated with the form are staying.</li>
<li>[SIGN-1007] - Replace using of GetTempFileName with GetRandomFileName.</li>
<li>SIGN-1013] - Signature 1: Audit log layout is broken.</li>
<li>[SIGN-1017] - Signature 1: Embed sign: Always shows the error popup, even if no error.</li>
<li>[SIGN-1020] - Notification emails are not send to the recipient with role CC.</li>
<li>[SIGN-1021] - Change the title of the audit log popup.</li>
<li>[SIGN-1022] - Signature 2: Javascript error in the signed envelope page.</li>
<li>[SIGN-1031] - Do not include the recipients that have role canSign false at the last page of the signed document.</li>
<li>[SIGN-1033] - Fixes in embed signing.</li>
<li>[SIGN-1034] - Signature template API: fields should not be assigned to the recipient with role CC.</li>
<li>[SIGN-1036] - Fix the viewer in signature 1.</li>
<li>[SIGN-1037] - Signature 2: Embed sign screen shows start button on each page.</li>
<li>[SIGN-1038] - Signature 2: Embed signed screen is not working in IE 8.</li>
<li>[SIGN-1039] - All dashboards in signature do not work IE8.</li>
</ul>
<h2><strong>GroupDocs Comparison</strong></h2>
<p><strong><a href="http://groupdocs.com/apps/comparison">GroupDocs Comparison</a></strong> is an online document comparison app that allows you to easily <strong><a href="http://groupdocs.com/apps/comparison/features">compare documents online</a></strong>. This way, you can monitor changes, consolidate different document versions and confirm that your documents are up to date. GroupDocs Comparison combines the two documents and highlights the difference in redline.</p>
<p><strong>Features Implemented</strong></p>
<ul>
<li>[DOCOMPARE-200] - Embeddable comparison result.</li>
</ul>
<p><strong>Improvements</strong></p>
<ul>
<li>[DOCOMPARE-211] - Confirm and embed dialog design update in comparison 2.</li>
</ul>
<p><strong>Bugs fixed</strong></p>
<ul>
<li>[DOCOMPARE-202] - Doc files comparison fails when there are embed images and ole objects.</li>
<li>[DOCOMPARE-204] - After first comparison, the GetChanges method is called multiple times.</li>
<li>[DOCOMPARE-205] - Can't load the output document after comparison is completed and the UI is blocked.</li>
<li>[DOCOMPARE-206] - Add embed button in comparison 2.</li>
<li>[DOCOMPARE-208] - Fixing issues in comparison 2 embed link generation and display.</li>
<li>[DOCOMPARE-212] - Comparing two different docx files fails.</li>
<li>[DOCOMPARE-213] - Comparing simple Excel files fails.</li>
<li>[DOCOMPARE-214] - Comparing pdf files fails.</li>
<li>[DOCOMPARE-215] - Comparing html files fails.</li>
<li>[DOCOMPARE-216] - Calling job-output API method with empty or null jobId should not be possible.</li>
<li>[DOCOMPARE-217] - Comparison 1: After the comparison completion, the results are not displayed.</li>
<li>[DOCOMPARE-219] - Comparison viewer not working because of changes in the viewer adapter.</li>
</ul>
<h2><strong>Platform</strong></h2>
<p><strong>Features Implemented</strong></p>
<ul>
<li>Major</li>
<ul>
<li>[CORE-859] Asynchronous PDF to XML conversion.</li>
<li>[CORE-858] Reusable file open dialog.</li>
<li>[CORE-873] Web hook trigger for the document viewing job.</li>
</ul>
</ul>
<ul>
<li>Minor</li>
<ul>
<li>[CORE-885] Integration with Aspose forums.</li>
</ul>
</ul>
<p><strong>Bugs fixed</strong></p>
<ul>
<li>Critical</li>
<ul>
<li>[CORE-884] Multiple instances of explorer plug-in do not work on the same page.</li>
<li>[CORE-892] Server-side processing fails for non-pdf file formats.</li>
</ul>
<li>Minor
<ul>
<li>[CORE-853] Custom-embedded logo cannot be reset.</li>
</ul>
</li>
</ul>
<h2><strong>Dashboard</strong></h2>
<p><strong>Features Implemented</strong></p>
<ul>
<li>Major
<ul>
<li>[CORE-831] Document post-upload processing indicator.</li>
</ul>
</li>
</ul>
<p><strong>Bugs fixed</strong></p>
<ul>
<li>Major:</li>
<ul>
<li>[CORE-840] Google Cloud. Dashboard convert redirects to null.</li>
<li>[CORE-882] "Upgrade" link points to old profile settings page.</li>
</ul>
</ul>
<ul>
<li>Minor</li>
<ul>
<li>[CORE-733] Folder lacks "Archive" context menu entry.</li>
<li>[CORE-793] Context menu for the last file is not full visible.</li>
<li>[CORE-844] Dashboard. Cannot cancel conversion.</li>
<li>[CORE-887] Chrome drag &amp; drop fail to upload multiple files.</li>
</ul>
</ul>
<h2><strong>API</strong></h2>
<p><strong>Features Implemented</strong></p>
<ul>
<li>[CORE-838] Dynabic subscription cancellation event handler.</li>
<li>[CORE-833] Pulling document pages image out of a 3rd-party storage.</li>
<li>[CORE-865] Generic prices for subscription plans support.</li>
<li>[CORE-869] Random file name generation function for storage providers.</li>
<li>[CORE-888] Document version number for document page image URL.</li>
<li>[CORE-889] Path.GetTempFileName replacement.</li>
<li>[CORE-893] Access level validation for file system folders.</li>
</ul>
<p><strong>Bugs fixed</strong></p>
<ul>
<li>[CORE-855] Large file uploads to Amazon S3 fails.</li>
<li>[CORE-866] Cannot upload PDF file.</li>
<li>[CORE-837] CSV file cannot be viewed.</li>
<li>[CORE-839] Update account user method creates users those already exist in the system.</li>
<li>[CORE-861] Number of users is not updated for Enterprise subscriptions.</li>
<li>[CORE-864] Thumbnails are not uploaded to Amazon when switching udf-pdf option on/off.</li>
<li>[CORE-871] Output document format is wrong for assembly jobs.</li>
<li>[CORE-872] Free space is improperly calculated on documents upload.</li>
<li>[CORE-387] <em>datasource.remove</em> returns 400 Bad Request</li>
<li>[CORE-389] <em>doc.questionnaire.remove</em> returns 400 Bad Request</li>
</ul>
<p>We'll bring you latest news on "Features &amp; Fixes" upon each new release, so stay tuned!</p>
]]></content:encoded>
			<wfw:commentRss>http://groupdocs.com/blog/groupdocs-apps-v2-4-features-and-fixes/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to perform Callbacks with GroupDocs PHP SDK</title>
		<link>http://groupdocs.com/blog/how-to-perform-callbacks-with-groupdocs-php-sdk</link>
		<comments>http://groupdocs.com/blog/how-to-perform-callbacks-with-groupdocs-php-sdk#comments</comments>
		<pubDate>Fri, 19 Apr 2013 13:25:08 +0000</pubDate>
		<dc:creator>Derek</dc:creator>
				<category><![CDATA[Tech Blog]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[document collaboration]]></category>
		<category><![CDATA[document management]]></category>
		<category><![CDATA[online document management system]]></category>
		<category><![CDATA[php api]]></category>

		<guid isPermaLink="false">http://groupdocs.com/blog/?p=2057</guid>
		<description><![CDATA[This article explains the basics of using PHP SDK callbacks. In this article I'll use the Convert API. Find information about other methods in the Swagger explorer. Requirements PHP 5.3 Apache ModRewrite PHP Curl extension PHP Sockets extension (php_sockets.dll) GroupDocs PHP SDK composer.phar (Download from http://getcomposer.org/download/ or use the included version) FatFree framework (https://github.com/bcosca/fatfree) We [...]]]></description>
			<content:encoded><![CDATA[<p>This article explains the basics of using PHP SDK callbacks. In this article I'll use the Convert API. <a href="https://api.groupdocs.com/v2.0/spec/" rel="nofollow">Find information about other methods in the Swagger explorer</a>.</p>
<h2><a name="Article14-HowtoperformCallbackswithGroupDocsPHPSDK-Requirements"></a>Requirements</h2>
<ul>
<li>PHP 5.3</li>
<li>Apache ModRewrite</li>
<li>PHP Curl extension</li>
<li>PHP Sockets extension (php_sockets.dll)</li>
<li>GroupDocs <a href="https://github.com/groupdocs/groupdocs-php" rel="nofollow">PHP SDK</a></li>
<li>composer.phar (Download from <a href="http://getcomposer.org/download/" rel="nofollow">http://getcomposer.org/download/</a> or use the included version)</li>
<li>FatFree framework (<a href="https://github.com/bcosca/fatfree" rel="nofollow">https://github.com/bcosca/fatfree</a>)</li>
</ul>
<p>We already know how to install the Fatfree framework and prepare for creating the sample from the <a href="http://groupdocs.com/blog/tech-blog/archive/2013/03/01/how-to-convert-files-with-groupdocs-php-sdk.html" rel="nofollow">previous article</a>. So lets start with the magic.</p>
<h2><a name="Article14-HowtoperformCallbackswithGroupDocsPHPSDK-Theory"></a>Theory</h2>
<p>First of all let's familiarize ourselves with Callback and the logic we will implement.</p>
<h3><a name="Article14-HowtoperformCallbackswithGroupDocsPHPSDK-Callback"></a>Callback</h3>
<p>A callback is something like "Action" in HTML forms, a URL that will be executed by the server when a job is done. In this article we will use the Convert API and Convert method to convert a file from DOC to PDF. One of parameters of this method is a callback URL.</p>
<h3><a name="Article14-HowtoperformCallbackswithGroupDocsPHPSDK-Thelogic"></a>The logic</h3>
<ol>
<li>User enters data into the form.</li>
<li>The data is transfered by POST to the controller.</li>
<li>The controller processes the received data (converts the file) and writes the user ID and private key to the text file for the Callback handler. After that, the controller returns the converted file GUID to the template.</li>
<li>After conversion, the server calls the callback handler.</li>
<li>The callback handler reads the user ID and private key from text file and makes a request to the Storage API to download the converted file.</li>
<li>At same time that the server calls the callback URL, the template file shows the conversion results in an <strong>iframe</strong> and sends an Ajax request to the Ajax handler.</li>
<li>The Ajax handler checks the "downloads" folder for the downloaded file. If file is there, handler gets the file name and returns it to the template.</li>
<li>If file was downloaded, Ajax also sends a request to the download file handler to generate the download file dialog.</li>
</ol>
<h2><a name="Article14-HowtoperformCallbackswithGroupDocsPHPSDK-Practice"></a>Practice</h2>
<p>Now we must create our files:</p>
<ul>
<li>The first file is the template file in the <strong>template</strong> folder.</li>
<li>The second file is the controller which is saved to the <strong>inc_samples</strong> folder.</li>
<li>THe other two files live in the <strong>callbacks</strong> subfolder in the <strong>inc_samples</strong> folder.</li>
</ul>
<p>The structure looks like this:</p>
<p><a href="http://groupdocs.com/blog/wp-content/uploads/2013/04/Figure-11.png"><img class="alignnone size-full wp-image-2061" title="Figure 1" src="http://groupdocs.com/blog/wp-content/uploads/2013/04/Figure-11.png" alt="Figure 11 How to perform Callbacks with GroupDocs PHP SDK"  /></a></p>
<p>As you can see from screenshot we must create five files:</p>
<ol>
<li>template.htm</li>
<li>controller.php</li>
<li>convert_callback.php</li>
<li>check_file.php</li>
<li>download_file.php</li>
</ol>
<p>So let's start in stages.</p>
<h3><a name="Article14-HowtoperformCallbackswithGroupDocsPHPSDK-template.html"></a>template.html</h3>
<p>In the <strong>template</strong> folder, create the <strong>template.htm</strong> file. This file shows the page with the input form and performs an Ajax request. Now put in this code:</p><pre class="crayon-plain-tag">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
    &lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/&gt;
    &lt;title&gt;Powered by {{ @VERSION }}&lt;/title&gt;
    &lt;style type="text/css"&gt;
        {{ Web::minify('templates/',array('style.css'),FALSE) }}
    &lt;/style&gt;
	&lt;script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" &gt;&lt;/script&gt;
&lt;/head&gt;
&lt;body&gt;

&lt;h3 style="text-align:center;"&gt;&lt;a href="/index.php"&gt;GroupDocs PHP SDK Samples&lt;/a&gt; - Convert&lt;/h3&gt;

&lt;div class='samplecontent' style="padding:10px;"&gt;
    &lt;span class="description"&gt;&lt;i&gt;This sample will show how to convert Doc to Docx, Docx to Doc, Docx and DOC to PDF and PPT to PDF, HTML to DOC and DOCX using PHP SDK&lt;/i&gt;&lt;/span&gt; &lt;br/&gt;
    &lt;br /&gt;
    &lt;span class="documentation"&gt;&lt;a href="/docs/sample18.html"&gt;Docs for this sample&lt;/a&gt;&lt;/span&gt;
    &lt;br /&gt;
    &lt;p&gt;&lt;font color="green"&gt;You entered: &lt;/font&gt;&lt;/p&gt;
		&lt;p&gt;ClientID = {{@userId}}&lt;/p&gt;
		&lt;p&gt;Private Key = {{@privateKey}}&lt;/p&gt;
		&lt;p&gt;File Id = {{@fileId}} &lt;/p&gt;
		&lt;p&gt;Convert type = {{@convert_type}}&lt;/p&gt;
    &lt;br /&gt;
    &lt;p&gt;&lt;font color="red"&gt;{{@error}}&lt;/font&gt;
    &lt;div id="requestForm" style="padding:20px; border:1px solid black;"&gt;
        &lt;p&gt; Enter data for request and press "Make request" button &lt;/p&gt;
        &lt;form action="/controller" method = "post" enctype = 'multipart/form-data'&gt;
            &lt;label for='client_id'&gt;GroupDocs Client ID&lt;/label&gt;
            &lt;br /&gt;
            &lt;input type='text', name='client_id' value="{{@userId}}" /&gt;
            &lt;br /&gt;
            &lt;label for='private_key'&gt;GroupDocs Private Key&lt;/label&gt;
            &lt;br /&gt;
            &lt;input type='text', name='private_key'  value="{{@privateKey}}" /&gt;
            &lt;br /&gt;
            &lt;label for='private_key' id="guid"&gt;GroupDocs fileID&lt;/label&gt;
            &lt;br /&gt;
            &lt;input type='text', name='fileId' id="guidfield" value="{{@fileId}}" /&gt;
            &lt;br /&gt;
            &lt;label for='callbackUrl'&gt;callbackUrl&lt;span class="optional"&gt;(Optional)&lt;/span&gt;&lt;/label&gt;
            &lt;br /&gt;
            &lt;input type='text', name='callbackUrl'  value="{{@callbackUrl}}" /&gt;
            &lt;br /&gt;
            &lt;input type='submit' value='Make Request'/&gt;
            &lt;select name="convert_type" id="convert_type"&gt;
                            &lt;option value="doc"&gt;Doc&lt;/option&gt;
                            &lt;option value="pdf"&gt;PDF&lt;/option&gt;
                            &lt;option value="docx"&gt;Docx&lt;/option&gt;
                            &lt;option value="ppt"&gt;PPT&lt;/option&gt;
            &lt;/select&gt;
            &lt;span id="results_status" style="color:red;display:none;"&gt; (Please wait for ajax response) &lt;/span&gt;
            &lt;div id="link"&gt;&lt;/div&gt;
        &lt;/form&gt;
        &lt;br /&gt;
        &lt;iframe id="downloadframe" style="display:none"&gt;&lt;/iframe&gt;
    &lt;/div&gt;
    &lt;div  id="result" style="padding:20px; border:1px solid black;"&gt;
        &lt;p&gt; Results: &lt;/p&gt;
        &lt;p&gt;&lt;font color="red"&gt;{{@error_message}}&lt;/font&gt;
        &lt;iframe src="{{ @iframe }}"&gt;&lt;/iframe&gt;
    &lt;/div&gt;
&lt;/div&gt;

 &lt;script type="text/javascript"&gt;
     $(document).ready(setTimeout(check, 5000));

         function check() {

             if (($("input[name=callbackUrl]").val() != "") &amp;&amp; (document.getElementById("result") != null)) {
                 $('#results_status').fadeIn("slow");
                 form = document.forms.form;
                 $.ajax({
                     type: 'POST',
                     url: '/callbacks/check_file',
                     success: function (data) {
                         $('#results_status').fadeOut("slow");
                         div = document.getElementById("link");
                         p = document.createElement("p");
                         p.innerHTML = "&lt;br /&gt; File " + data + " was downloaded.";
                         div.appendChild(p);
                         $("#downloadframe").attr("src", "/callbacks/download_file?FileName=" + data);
                     },
                     dataType: "text"
                 });
             }
         }

&lt;/script&gt;
&lt;/body&gt;
&lt;/html&gt;</pre><p>&nbsp;</p>
<p>I will not explain the HTML part of this code since it is a usual HTML document. But we have a JavaScript so let's take a look at that.</p>
<p>First we must include a Jquery library for Ajax requests. This code in the "Head" is responsible for this:</p><pre class="crayon-plain-tag">&lt;script src="//ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js" &gt;&lt;/script&gt;</pre><p>After that we can use Ajax. Now the Ajax code:</p><pre class="crayon-plain-tag">&lt;script type="text/javascript"&gt;
     $(document).ready(setTimeout(check, 5000)); //Wait 5 sec. after page loaded and run "check" function

         function check() {

             if (($("input[name=callbackUrl]").val() != "") &amp;&amp; (document.getElementById("result") != null)) { //Check is this first time page loaded
                 $('#results_status').fadeIn("slow"); //Chow message

                //Ajax request
               $.ajax({
                     type: 'POST',                     //Set ajax request type to POST
                     url: '/callbacks/check_file',     //Action to which send request
                     success: function (data) {        //If request success exeсute function
                         $('#results_status').fadeOut("slow");     //Show result status
                         div = document.getElementById("link");    //Get element with id "link"
                         p = document.createElement("p");          //Create new HTML element
                         p.innerHTML = "&lt;br /&gt; File " + data + " was downloaded.";          //Set content for new HTML element
                         div.appendChild(p);                                               //Add new element to the element with id "link"
                         $("#downloadframe").attr("src", "/callbacks/download_file?FileName=" + data);  //Make request to download file_file controller
                     },
                     dataType: "text"               //Set data type which will get ajax request from controller

                 });
             }
         }

&lt;/script&gt;</pre><p>&nbsp;</p>
<p>As Jquery is a JavaScript library we must use the <tt>&lt;script&gt;&lt;/script&gt;</tt> tag's. This code starts work 5 sec. after the page is loaded. The delay is necessary in order that the iframe with results is loaded. First of all we must check if this is first time the page is loaded. For this reason we use this check:</p>
<div>
<div>
<pre class="crayon-plain-tag">if (($("input\[name=callbackUrl\]").val() \!= "") &amp;&amp; (document.getElementById("result") \!= null)) {</pre>
</div>
</div>
<p>After this check, the script shows message and receives all elements from the document. Then the script builds and sends an Ajax request to the <strong>check_file</strong> controller. When the controller returns the downloaded file name, Ajax sends it to the <strong>download_file</strong> controller.</p>
<h3><a name="Article14-HowtoperformCallbackswithGroupDocsPHPSDK-controller.php"></a>controller.php</h3>
<p>Now lets do the next step and see what our base controller looks like. In the <strong>inc_samples</strong> folder, create a <strong>file _controller.php</strong> file. This file gets form data from the template and makes requests to the Async API to convert the file. Also this controller creates a text file with the user ID and private key for the callback controllers because we can't send this data any other way and the callback controller will be requested only by the server by the callback URL.</p>
<p>Now I'll show you the <strong>controller.php</strong> code. Put it in:</p><pre class="crayon-plain-tag">&lt;?php
    //### This sample will show how to insert Assembly questionnaire into webpage using PHP SDK

    //### Set variables and get POST data
    F3::set('userId', '');
    F3::set('privateKey', '');
    F3::set('fileId', '');
    F3::set('convert_type', '');
    $clientId = F3::get('POST["client_id"]');
    $privateKey = F3::get('POST["private_key"]');
    $convert_type = F3::get('POST["convert_type"]');
    $fileGuId = f3::get('POST["fileId"]');

    function Convert($clientId, $privateKey, $convert_type, $fileGuId) {
        if (empty($clientId)|| empty($privateKey) || empty($convert_type) || empty($fileGuId)) {
            throw new Exception('Please enter all required parameters');
        } else {
            //path to settings file - temporary save userId and apiKey like to property file
            $infoFile = fopen(__DIR__ . '/../user_info.txt', 'w');
            fwrite($infoFile, $clientId . "\r\n" . $privateKey);
            fclose($infoFile);
             //check if Downloads folder exists and remove it to clean all old files
            if (file_exists(__DIR__ . '/../downloads')) {
                delFolder(__DIR__ . '/../downloads/');
            }
             //Set variables for Viewer
            F3::set('userId', $clientId);
            F3::set('privateKey', $privateKey);
            //###Create Signer, ApiClient and Storage Api objects

            //Create signer object
            $signer = new GroupDocsRequestSigner($privateKey);
            //Create apiClient object
            $apiClient = new APIClient($signer);
            //Create AsyncApi object
            $api = new AsyncApi($apiClient);
            //Create Storage Api object
            $apiStorage = new StorageApi($apiClient);
            //Get entered callback url
            $callbackUrl = f3::get('POST["callbackUrl"]');
            F3::set("callbackUrl", $callbackUrl);
            //Make request to api for convert file
            $convert = $api-&gt;Convert($clientId, $fileGuId, null, null, null, $callbackUrl, $convert_type);
            //Check request status
            if($convert-&gt;status == "Ok") {
                //Delay necessary that the inquiry would manage to be processed
                sleep(5);
                //Make request to api for get document info by job id
                $jobInfo = $api-&gt;GetJobDocuments($clientId, $convert-&gt;result-&gt;job_id, "");
                if ($jobInfo-&gt;result-&gt;inputs[0]-&gt;outputs[0]-&gt;guid != "") {
                    //Get file guid
                    $guid = $jobInfo-&gt;result-&gt;inputs[0]-&gt;outputs[0]-&gt;guid;
                } else {
                    throw new Exception('File GuId is empty');
                }
                //Generation of iframe URL using fileGuId
                $iframe = 'http://apps.groupdocs.com/document-viewer/embed/' . $guid . '" frameborder="0" width="100%" height="600"';
            } else {
                $error_message = $convert-&gt;error_message;
                return f3::set('error_message', $error_message);
            }
            //If request was successfull - set url variable for template
            F3::set('fileId', $fileId);
            return F3::set('iframe', $iframe);
        }
    }
    //### Delete downloads folder and all files in this folder
    function delFolder($path) {
        $item = array();
        //Get all items fron folder
        $item = scandir($path);
        //Remove from array "." and ".."
        $item = array_slice($item, 2);
        //Check is there was files
        if (count($item) &gt; 0) {
            //Delete files from folder
            for ($i = 0; $i &lt; count($item); $i++) {
                $next = $path . "\\" . $item[$i];
                if (file_exists($next)) {
                    unlink($next);
                }
            }
        }
        //Delete folder
        rmdir($path);
    }

    try {
        Convert($clientId, $privateKey, $convert_type, $fileGuId);
    } catch (Exception $e) {
        $error = 'ERROR: ' .  $e-&gt;getMessage() . "\n";
        f3::set('error', $error);
    }
    F3::set('userId', $clientId);
    F3::set('privateKey', $privateKey);
    F3::set('convert_type', $convert_type);
    // Process template
    echo Template::serve('template.htm');</pre><p>&nbsp;</p>
<p>I won't go through the code in detail: each line is explained in the comments. But I'll explain briefly what the code doing.</p>
<p>We have two functions, <tt>Convert</tt> and <tt>delFolder</tt>, which do all the work. First of all, we receive POST data from the template and check if all the required fields are filled in. If they are, the controller creates a text file and writes the user ID and private key to it. After that follows the creation of the <tt>GroupDocsRequestSigner</tt>, <tt>APIClient</tt> and Async API objects so that we can send request to the API. So we have created all the objects and now we can convert the file. To do this we only need to call the <tt>convert</tt> method and transfer to it the:</p>
<ul>
<li>user ID,</li>
<li>GUID of the file in the <a href="http://groupdocs.com/" rel="nofollow">GroupDocs</a> account which will be converted</li>
<li>callback URL</li>
<li>format to convert the file to.</li>
</ul>
<p>Now we have converted the file but we need the GUID of the converted file and only the job ID is returned from the converted method. No problem, lets take 5 sec. to rest. The 5 sec. delay is necessary so that the inquiry can be be processed. After the delay, we take the returned job ID and make new request to the Async API but now with <tt>GetJobDocuments</tt> which returns all the info we need by job ID. Now we have the GUID for the converted file and can give this GUID to the iframe URL and return the URL to the template which will use it in the iframe source.</p>
<p>The second function checks the <strong>downloads</strong> folder for old files and deletes them.</p>
<h3><a name="Article14-HowtoperformCallbackswithGroupDocsPHPSDK-convertcallback.php"></a>convert_callback.php</h3>
<p>Next, let's take a look at the callback controller, <strong>convert_callback.php</strong>. This file gets the callback from server, takes the data the server sends and downloads the converted file.</p><pre class="crayon-plain-tag">&lt;?php
    //Local path to the text file with user data
    $userInfo = file(__DIR__ . '/../../user_info.txt');
    //Get user data from text file
    $clientId = $userInfo[0];
    $privateKey = $userInfo[1];
    //Get raw data
    $json = file_get_contents("php://input");
    //Decode json with raw data to array
	$callBack_data = json_decode($json, true);
    //Get job id from array
	$jobId = $callBack_data["SourceId"];

    //Create signer object
    $signer = new GroupDocsRequestSigner(trim($privateKey));
    //Create apiClient object
    $apiClient = new APIClient($signer);
    //Create AsyncApi object
    $api = new AsyncApi($apiClient);
    //Create Storage Api object
    $apiStorage = new StorageApi($apiClient);
	sleep(5);
    //Make request to Async API to get job info
	$jobInfo = $api-&gt;GetJobDocuments(trim($clientId), $jobId, "");
	if ($jobInfo-&gt;status == "Ok") {
		   //Get file guid
            $guid = $jobInfo-&gt;result-&gt;inputs[0]-&gt;outputs[0]-&gt;guid;
            //Get file name
            $name = $jobInfo-&gt;result-&gt;inputs[0]-&gt;outputs[0]-&gt;name;

    }
    //Local path to the downloads folder
    $downloadFolder = dirname(__FILE__). '/../../downloads';
    //Check is folder exist
    if (!file_exists($downloadFolder)) {
        //If folder don't exist create it
        mkdir($downloadFolder);
    }
    //Obtaining file stream of downloading file and definition of folder where to download file
    $outFileStream =  FileStream::fromHttp($downloadFolder, $name);
    //Download file from GroupDocs.
    $download = $apiStorage-&gt;GetFile(trim($clientId), $guid, $outFileStream);

?&gt;</pre><p>This controller reads the user ID and private key from the text file. Then it gets the raw data from the server inquiry. In this raw data we have the job ID. Use this like in the previous controller to get the converted file. To do this we must create all the objects again: <tt>GroupDocsRequestSigner</tt>, <tt>APIClient</tt> and Async API. After that we can make a request using the <tt>GetJobDocuments</tt> method to get the file GUID and name. Use this data for the <tt>GetFile</tt> method to download the converted file to the <strong>downloads</strong> folder.</p>
<h3><a name="Article14-HowtoperformCallbackswithGroupDocsPHPSDK-checkfile.php"></a>check_file.php</h3>
<p>At the same time that the <strong>convert_callback</strong> controller is working, we see that the page is reloaded and shows the iframe with the converted file. When the iframe is loaded, Ajax sends its request to the <strong>check_file</strong> controller.</p>
<p>The <strong>check_file</strong> controller looks like this:</p><pre class="crayon-plain-tag">&lt;?php

    $result = "";
    //counter to not wait forever
    $counter = 0;
    //Local path to the downloads folder
    $downloadFolder = __DIR__ . '/../../downloads';
	//Check folder for downloaded file
    do {
        //Set max. iterations
        if ($counter &gt;= 10) {
            $result = "Error";
            break;
        }
        sleep(5);
        //Check is downloads folder exist
        if (!file_exists($downloadFolder)) {
            //If folder don't exist create it
            $di = mkdir($downloadFolder);
        }
        //Open downloads folder
        $filePaths = opendir($downloadFolder);
        //Get all elements from folder
        while (($file = readdir($filePaths)) !== false) {
            //Get downloaded file name
            if ($file != "." &amp;&amp; $file != "..") {
                $name = $file;
            }
        }
        //Close folder
        closedir($filePaths);
        //Check is file downloaded
        if ($name == "") {
            //If file don't downloaded yet do one mor itaretion
            $counter++;
            continue;
        //If file downloaded get file name and break.
        } else {

            $result = $name; //get the name of the fist file in the directory
            break;
        }
    } while (true);
    //Check result
    if ($result == "Error") {
         return "File was not found. Looks like something went wrong.";
    }
	//Return file name to the template for ajax
    echo $result;
?&gt;</pre><p>This controller opens the <strong>downloads</strong> folder and gets all files from it. If there are no files, the controller waits for 5 sec. and checks again. When the file is downloaded and appear in the folder, the controller get the name and returns it to Ajax which sends the file name to the <strong>download_file</strong> controller.</p>
<h3><a name="Article14-HowtoperformCallbackswithGroupDocsPHPSDK-downloadfile.php"></a>download_file.php</h3>
<p>The <strong>download_file</strong> generates the download dialog.</p><pre class="crayon-plain-tag">&lt;?php
//Get downloaded file
$file = (dirname(__FILE__) . '/../../downloads/' . $_GET["FileName"]);
//Set data for download dialog
header ("Content-Type: application/octet-stream");
header ("Accept-Ranges: bytes");
header ("Content-Length: ".filesize($file));
header ("Content-Disposition: attachment; filename=".$_GET["FileName"]);
//Download file
readfile($file);
?&gt;</pre><p>Here we take full local path to the downloaded file and transfers it to the download dialog.</p>
<h2><a name="Article14-HowtoperformCallbackswithGroupDocsPHPSDK-Programinaction"></a>Program in action</h2>
<p>On that we are finished! Let me show you what it looks like in action:</p>
<div id="attachment_2068" class="wp-caption alignnone" ><a href="http://groupdocs.com/blog/wp-content/uploads/2013/04/The-input-form.png"><img class="size-full wp-image-2068" title="The input form" src="http://groupdocs.com/blog/wp-content/uploads/2013/04/The-input-form.png" alt="The input form How to perform Callbacks with GroupDocs PHP SDK" width="602" height="547" /></a><p class="wp-caption-text">The input form</p></div>
<p>&nbsp;</p>
<div id="attachment_2069" class="wp-caption alignnone" ><a href="http://groupdocs.com/blog/wp-content/uploads/2013/04/Ajax-message.png"><img class="size-full wp-image-2069" title="Ajax message" src="http://groupdocs.com/blog/wp-content/uploads/2013/04/Ajax-message.png" alt="Ajax message How to perform Callbacks with GroupDocs PHP SDK" width="602" height="66" /></a><p class="wp-caption-text">Ajax message</p></div>
<div id="attachment_2070" class="wp-caption alignnone" ><a href="http://groupdocs.com/blog/wp-content/uploads/2013/04/Iframe-with-converted-file.png"><img class="size-full wp-image-2070" title="Iframe with converted file" src="http://groupdocs.com/blog/wp-content/uploads/2013/04/Iframe-with-converted-file.png" alt="Iframe with converted file How to perform Callbacks with GroupDocs PHP SDK" width="602" height="360" /></a><p class="wp-caption-text">Iframe with converted file</p></div>
<p>&nbsp;</p>
<div id="attachment_2089" class="wp-caption alignnone" ><a href="http://groupdocs.com/blog/wp-content/uploads/2013/04/Download-dialog-FireFox1.png"><img class="size-full wp-image-2089" title="Download dialog (FireFox)" src="http://groupdocs.com/blog/wp-content/uploads/2013/04/Download-dialog-FireFox1.png" alt="Download dialog FireFox1 How to perform Callbacks with GroupDocs PHP SDK" width="602" height="484" /></a><p class="wp-caption-text">Download dialog (FireFox)</p></div>
]]></content:encoded>
			<wfw:commentRss>http://groupdocs.com/blog/how-to-perform-callbacks-with-groupdocs-php-sdk/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to Streamline Your Document Signing Using Online Signature?</title>
		<link>http://groupdocs.com/blog/how-to-streamline-your-document-signing-using-online-signature</link>
		<comments>http://groupdocs.com/blog/how-to-streamline-your-document-signing-using-online-signature#comments</comments>
		<pubDate>Fri, 12 Apr 2013 16:25:34 +0000</pubDate>
		<dc:creator>Derek</dc:creator>
				<category><![CDATA[GroupDocs Signature]]></category>
		<category><![CDATA[collect signatures online]]></category>
		<category><![CDATA[e-signature]]></category>
		<category><![CDATA[electronic signature]]></category>
		<category><![CDATA[esignature]]></category>
		<category><![CDATA[online signature]]></category>
		<category><![CDATA[sign documents online]]></category>

		<guid isPermaLink="false">http://groupdocs.com/blog/?p=1870</guid>
		<description><![CDATA[A steady document signing process is the back bone of any contract-oriented organization. Conventional signing process leaves you with piles of signed documents, difficult to handle and archive. Also, the documents are passed around different departments, either getting lost or eating up too much time delaying the signing process. Online signature is the answer to [...]]]></description>
			<content:encoded><![CDATA[<p>A steady document signing process is the back bone of any contract-oriented organization. Conventional signing process leaves you with piles of signed documents, difficult to handle and archive. Also, the documents are passed around different departments, either getting lost or eating up too much time delaying the signing process. Online signature is the answer to all these concerns.</p>
<h2>Save your time and effort with GroupDocs’ online signature</h2>
<p>Say good bye to lost signed documents and tons of paper piling up in your office! Embrace GroupDocs Signature, an efficient online signature service, to streamline your entire signing process. GroupDocs’ online signature service lets you easily prepare &amp; send documents to signers, and collect signatures online.</p>
<h2>Get peace of mind by tracking the signing process</h2>
<p>Track the document signing process from a centralized location. As soon as the documents are signed, they are automatically archived and available for retrieval when required. This completely avoids the chance of documents getting lost in mountains of signed contracts. In addition, there is no need to follow up your signers regularly through phone calls or emails. You can simply set a reminder while creating a new envelope (while preparing the document for signature) so that the signers get notifications automatically till the reminder expires.</p>
<h2>Efficient work flow walks you through the entire process</h2>
<p>The work flow for preparing the documents for signing and sending it is so simple that even novice people can do it without the help of any documentation. GroupDocs Signature walks you through the entire process step by step. The workflow is designed in such a way that you go to the next step only after finishing the present one. This will make sure that you perform the process correctly.</p>
<h2>Procedure for preparing and sending a document for online signature</h2>
<p>Now, lets see the simple steps for preparing a document for e-signature and sending them out to collect signatures:</p>
<ol>
<li>Go to Signature dashboard and start creating a new envelope.<br />
<a href="http://groupdocs.com/blog/wp-content/uploads/2013/04/Creating-a-new-envelope-for-e-signature8.png"><img class="alignnone size-full wp-image-2004" style="margin-top: 20px; margin-bottom: 20px;" title="Creating a new envelope for e-signature" src="http://groupdocs.com/blog/wp-content/uploads/2013/04/Creating-a-new-envelope-for-e-signature8.png" alt="Creating a new envelope for e signature8 How to Streamline Your Document Signing Using Online Signature?" width="600" height="209" /></a></li>
<li>
<h3>Step 1 - Choose a File:</h3>
<p>Here you have three options to choose a file. Use one of them to select your preferred document:</p>
<ol>
<li>Drag and drop the file in the DROP FILES HERE area.</li>
<li>Use the Upload button and select a file from your computer.</li>
<li>Use the Add from Library button to select a file from your GroupDocs repository.<br />
<a href="http://groupdocs.com/blog/wp-content/uploads/2013/04/Choose-a-file5.png"><img class="alignnone size-full wp-image-2005" style="margin-top: 20px; margin-bottom: 20px;" title="Choose a file" src="http://groupdocs.com/blog/wp-content/uploads/2013/04/Choose-a-file5.png" alt="Choose a file5 How to Streamline Your Document Signing Using Online Signature?" width="600" height="289" /></a></li>
</ol>
</li>
<li>
<h3>Step 2 - Add Recipients:</h3>
<ul>
<li>Add your signers or recipients here.<br />
<a href="http://groupdocs.com/blog/wp-content/uploads/2013/04/Add-recipients7.png"><img class="alignnone size-full wp-image-2006" style="margin-top: 20px; margin-bottom: 20px;" title="Add recipients" src="http://groupdocs.com/blog/wp-content/uploads/2013/04/Add-recipients7.png" alt="Add recipients7 How to Streamline Your Document Signing Using Online Signature?" width="600" height="396" /></a></li>
</ul>
</li>
<li>
<h3>Step 3 - Add Info (optional):</h3>
<ul>
<li>Add more details to the envelope. You can also add a watermark to your documents. This step is optional.<br />
<a href="http://groupdocs.com/blog/wp-content/uploads/2013/04/Add-ifo-to-the-envelope3.png"><img class="alignnone size-full wp-image-2007" style="margin-top: 20px; margin-bottom: 20px;" title="Add ifo to the envelope" src="http://groupdocs.com/blog/wp-content/uploads/2013/04/Add-ifo-to-the-envelope3.png" alt="Add ifo to the envelope3 How to Streamline Your Document Signing Using Online Signature?" width="600" height="664" /></a></li>
</ul>
</li>
<li>
<h3>Step 4 - Add Reminders (optional):</h3>
<ul>
<li>Add reminder, deadline and document expiry in this step. This too is optional.<br />
<a href="http://groupdocs.com/blog/wp-content/uploads/2013/04/Add-reminder-deadlines-and-document-expiry4.png"><img class="alignnone size-full wp-image-2008" style="margin-top: 20px; margin-bottom: 20px;" title="Add reminder, deadlines, and document expiry" src="http://groupdocs.com/blog/wp-content/uploads/2013/04/Add-reminder-deadlines-and-document-expiry4.png" alt="Add reminder deadlines and document expiry4 How to Streamline Your Document Signing Using Online Signature?" width="600" height="353" /></a></li>
</ul>
</li>
<li>
<h3>Step 5 - Add Fields:</h3>
<ul>
<li>Drag and drop fields to the required location on the uploaded document.<br />
<a href="http://groupdocs.com/blog/wp-content/uploads/2013/04/Add-signature-and-other-fields-to-the-document2.png"><img class="alignnone size-full wp-image-2009" style="margin-top: 20px; margin-bottom: 20px;" title="Add signature and other fields to the document" src="http://groupdocs.com/blog/wp-content/uploads/2013/04/Add-signature-and-other-fields-to-the-document2.png" alt="Add signature and other fields to the document2 How to Streamline Your Document Signing Using Online Signature?" width="600" height="275" /></a></li>
</ul>
</li>
<li>
<h3>Step 6 - Summary (optional):</h3>
<ul>
<li>Review the envelope one final time and send the document to the signer(s).<br />
<a href="http://groupdocs.com/blog/wp-content/uploads/2013/04/Review-the-envelope-on-final-time-and-send-the-document-to-the-signers2.png"><img class="alignnone size-full wp-image-2010" style="margin-top: 20px; margin-bottom: 20px;" title="Review the envelope on final time and send the document to the signer(s)" src="http://groupdocs.com/blog/wp-content/uploads/2013/04/Review-the-envelope-on-final-time-and-send-the-document-to-the-signers2.png" alt="Review the envelope on final time and send the document to the signers2 How to Streamline Your Document Signing Using Online Signature?" width="600" height="296" /></a></li>
<li>The signers can then easily sign documents online just using a browser. Type, draw, or upload the signature.<br />
<a href="http://groupdocs.com/blog/wp-content/uploads/2013/04/Type-draw-or-upload-your-signature2.png"><img class="alignnone size-full wp-image-2011" style="margin-top: 20px; margin-bottom: 20px;" title="Type, draw or upload your signature" src="http://groupdocs.com/blog/wp-content/uploads/2013/04/Type-draw-or-upload-your-signature2.png" alt="Type draw or upload your signature2 How to Streamline Your Document Signing Using Online Signature?" width="600" height="322" /></a></li>
</ul>
</li>
</ol>
<p>All related partied are notified as soon as the documents are signed.<br />
Stay tuned for a step-by-step video tutorial on how to prepare and send a document for online signature, it's in the pipeline. So why wait! go green with this efficient e-signature service.</p>
]]></content:encoded>
			<wfw:commentRss>http://groupdocs.com/blog/how-to-streamline-your-document-signing-using-online-signature/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How to Compare Files with GroupDocs PHP SDK</title>
		<link>http://groupdocs.com/blog/how-to-compare-files-with-groupdocs-php-sdk</link>
		<comments>http://groupdocs.com/blog/how-to-compare-files-with-groupdocs-php-sdk#comments</comments>
		<pubDate>Fri, 12 Apr 2013 14:44:45 +0000</pubDate>
		<dc:creator>Derek</dc:creator>
				<category><![CDATA[Tech Blog]]></category>
		<category><![CDATA[API]]></category>
		<category><![CDATA[document comparison]]></category>
		<category><![CDATA[GroupDocs API]]></category>
		<category><![CDATA[GroupDocs API SDK]]></category>
		<category><![CDATA[GroupDocs Comparison]]></category>

		<guid isPermaLink="false">http://groupdocs.com/blog/?p=1857</guid>
		<description><![CDATA[This article explains the basics of using PHP SDK classes and methods. In this article I'll use the Comparison API and show how to compare two documents from a GroupDocs account. Find information about other methods in the Swagger explorer. Requirements PHP 5.3 Apache ModRewrite PHP Curl extension PHP Sockets extension (php_sockets.dll) GroupDocs PHP SDK [...]]]></description>
			<content:encoded><![CDATA[<p>This article explains the basics of using PHP SDK classes and methods. In this article I'll use the Comparison API and show how to compare two documents from a GroupDocs account. <a href="https://api.groupdocs.com/v2.0/spec/" rel="nofollow">Find information about other methods in the Swagger explorer</a>.</p>
<h2>Requirements</h2>
<ul>
<li>PHP 5.3</li>
<li>Apache ModRewrite</li>
<li>PHP Curl extension</li>
<li>PHP Sockets extension (php_sockets.dll)</li>
<li>GroupDocs <a href="https://github.com/groupdocs/groupdocs-php" rel="nofollow">PHP SDK</a></li>
<li>composer.phar (Download from <a href="http://getcomposer.org/download/" rel="nofollow">http://getcomposer.org/download/</a> or use the included version)</li>
<li>FatFree framework (<a href="https://github.com/bcosca/fatfree" rel="nofollow">https://github.com/bcosca/fatfree</a>)</li>
</ul>
<p>We already know how to install the Fatfree framework and prepare for creating the sample from the <a href="http://groupdocs.com/blog/tech-blog/archive/2013/03/01/how-to-convert-files-with-groupdocs-php-sdk.html" rel="nofollow">previous article</a>. So lets start with the magic.</p>
<h2>Sample Creation: Creating the Template</h2>
<p>Create a template file in the template folder and name it <strong>Comparison.htm</strong>. This generates a web page with a form for entering the necessary data such as user ID, private key and the file GUIDs for the two files that will be compared. The user can also enter a callback URL. How to get this data you can find out <a href="http://groupdocs.com/docs/display/gendoc/Home" rel="nofollow">in the documentation.</a></p><pre class="crayon-plain-tag">&lt;!DOCTYPE html&gt;
&lt;html lang="en"&gt;
&lt;head&gt;
	&lt;meta http-equiv="Content-Type" content="text/html; charset=UTF-8"/&gt;
	&lt;title&gt;Powered by {{ @VERSION }}&lt;/title&gt;
	&lt;style type="text/css"&gt;
		{{ Web::minify('templates/',array('style.css'),FALSE) }}
	&lt;/style&gt;
&lt;/head&gt;
&lt;body&gt;
&lt;h3 style="text-align:center;"&gt;&lt;a href="/index.php"&gt;GroupDocs PHP SDK Samples&lt;/a&gt; - Comparison&lt;/h3&gt;

&lt;div class='samplecontent' style="padding:10px;"&gt;
   &lt;i&gt;This sample will show how to Compare documents using PHP SDK&lt;/i&gt; &lt;br/&gt;

   &lt;br/&gt;&lt;p&gt;You entered:
   &lt;p&gt;ClientID = {{@userId}}
   &lt;p&gt;PrivateKey = {{@privateKey}}
   &lt;p&gt;Source file Id = {{@sourceFileId}}
   &lt;p&gt;Target file Id = {{@targetFileId}}
   &lt;p&gt;Call back url = {{@callbackURL}}

   &lt;div id="requestForm" style="padding:20px; border:1px solid black;"&gt;
   &lt;p&gt; Enter data for request and press "Make request" button &lt;/p&gt;
        &lt;form action="/comparison" method = "post" enctype = 'multipart/form-data'&gt;
            &lt;label for='client_id'&gt;GroupDocs ClientID&lt;/label&gt;
            &lt;br /&gt;
            &lt;input type='text', name='client_id' value="{{@userId}}" /&gt;
            &lt;br /&gt;
            &lt;label for='private_key'&gt;GroupDocs PrivateKey&lt;/label&gt;
            &lt;br /&gt;
            &lt;input type='text', name='private_key'  value="{{@privateKey}}" /&gt;
            &lt;br /&gt;
            &lt;label for='sourceFileId'&gt;sourceFileId&lt;/label&gt;
            &lt;br /&gt;
            &lt;input type='text', name='sourceFileId'  value="{{@sourceFileId}}" /&gt;
            &lt;br /&gt;
            &lt;label for='targetFileId'&gt;targetFileId&lt;/label&gt;
            &lt;br /&gt;
            &lt;input type='text', name='targetFileId'  value="{{@targetFileId}}" /&gt;
            &lt;br /&gt;
            &lt;label for='callbackUrl'&gt;callbackUrl&lt;/label&gt;
            &lt;br /&gt;
            &lt;input type='text', name='callbackUrl'  value="{{@callbackURL}}" /&gt;
            &lt;br /&gt;
            &lt;input type='submit' value='Make Request'/&gt;
        &lt;/form&gt;
   &lt;/div&gt;
   &lt;div  style="padding:20px; border:1px solid black;"&gt;
        &lt;p&gt; Results: &lt;/p&gt;
        &lt;iframe src={{@iframe}}&gt;&lt;/iframe&gt;
   &lt;/div&gt;
   &lt;br/&gt;
&lt;/div&gt;

&lt;/body&gt;
&lt;/html&gt;</pre><p></p>
<h3>The Template Code Explained</h3>
<p>This code block shows the data the user entered. Here you can see code like this: <tt>\{\{@userId\}\}</tt>. In the Fatfree framework you must call a variable declared in the controller for the template.</p><pre class="crayon-plain-tag">&lt;br/&gt;&lt;p&gt;You entered:
   &lt;p&gt;ClientID = {{@userId}}
   &lt;p&gt;PrivateKey = {{@privateKey}}
   &lt;p&gt;Source file Id = {{@sourceFileId}}
   &lt;p&gt;Target file Id = {{@targetFileId}}
   &lt;p&gt;Call back url = {{@callbackURL}}</pre><p>The next step in the template file creates a div block with the form for entering data:</p><pre class="crayon-plain-tag">&lt;div id="requestForm" style="padding:20px; border:1px solid black;"&gt;
   &lt;p&gt; Enter data for request and press "Make request" button &lt;/p&gt;
        &lt;form action="/sample19" method = "post" enctype = 'multipart/form-data'&gt;
            &lt;label for='client_id'&gt;GroupDocs ClientID&lt;/label&gt;
            &lt;br /&gt;
            &lt;input type='text', name='client_id' value="{{@userId}}" /&gt;
            &lt;br /&gt;
            &lt;label for='private_key'&gt;GroupDocs PrivateKey&lt;/label&gt;
            &lt;br /&gt;
            &lt;input type='text', name='private_key'  value="{{@privateKey}}" /&gt;
            &lt;br /&gt;
            &lt;label for='sourceFileId'&gt;sourceFileId&lt;/label&gt;
            &lt;br /&gt;
            &lt;input type='text', name='sourceFileId'  value="{{@sourceFileId}}" /&gt;
            &lt;br /&gt;
            &lt;label for='targetFileId'&gt;targetFileId&lt;/label&gt;
            &lt;br /&gt;
            &lt;input type='text', name='targetFileId'  value="{{@targetFileId}}" /&gt;
            &lt;br /&gt;
            &lt;label for='callbackUrl'&gt;callbackUrl&lt;/label&gt;
            &lt;br /&gt;
            &lt;input type='text', name='callbackUrl'  value="{{@callbackURL}}" /&gt;
            &lt;br /&gt;
            &lt;input type='submit' value='Make Request'/&gt;
        &lt;/form&gt;
   &lt;/div&gt;</pre><p></p>
<h4>Callbacks</h4>
<p>Let's explain some key moments for this code. In the Fatfree framework, the form is creation using a simple HTML code which does not need explaining: everything is as usual. But in the value of the input's we transfer the value of variables from the controller - <tt>\{\{@userId\}\}</tt> - in order that the user data stays in the values when the user clicks <strong>Make request</strong>.</p>
<p>Also you can see here the input named <strong>CallbackURL</strong>. In this field, the user can enter a URL which will be executed by the server after the comparison is done. A callback is something like an action for a form. It can be a PHP file which is triggered by the server. All of these fields are required except for the <strong>callbackURL</strong> field.</p>
<h4>Displaying the Comparison Results</h4>
<p>The next code block in the template file is:</p><pre class="crayon-plain-tag">&lt;div  style="padding:20px; border:1px solid black;"&gt;
        &lt;p&gt; Results: &lt;/p&gt;
           &lt;p&gt;&lt;font color="red"&gt;{{@error}}&lt;/font&gt;           &lt;iframe src={{@iframe}}&gt;&lt;/iframe&gt;
   &lt;/div&gt;
   &lt;br/&gt;
&lt;/div&gt;</pre><p>This div block shows the results of a comparison. As you can see, it's simple HTML too but the iframe source and parameters we get from the controller. As part of the controller operation, we check that all the parameters have been entered. If a parameter doesn't have a value, an error is returned. So, depending on what we receive from the server, we return either the iframe or an error message.</p>
<p>The form looks like this:</p>
<p><a href="http://groupdocs.com/blog/wp-content/uploads/2013/04/form.png"><img class="alignnone size-full wp-image-1860" title="form" src="http://groupdocs.com/blog/wp-content/uploads/2013/04/form.png" alt="form How to Compare Files with GroupDocs PHP SDK"  /></a></p>
<h2>Sample Creation: Creating the Controller</h2>
<p>Go to the <strong>inc_samples</strong> folder and create controller file called <strong>Comparison.php</strong>.</p>
<p>This file will contain this code:</p><pre class="crayon-plain-tag">&lt;?php
    //&lt;i&gt;This sample will show how to use &lt;b&gt;Compare&lt;/b&gt; method from ComparisonApi to return a URL representing a single page of a Document&lt;/i&gt;

    //###Set variables and get POST data
    F3::set('userId', '');
    F3::set('privateKey', '');
    f3::set('result', "");
    $clientId = F3::get('POST["client_id"]');
    $privateKey = F3::get('POST["private_key"]');
    $sourceFileId = f3::get('POST["sourceFileId"]');
    $targetFileId = f3::get('POST["targetFileId"]');
    $callbackUrl = f3::get('POST["callbackUrl"]');
    $basePath = f3::get('POST["server_type"]');

    function Compare($clientId, $privateKey, $sourceFileId, $targetFileId, $callbackUrl, $basePath)
    {
         //### Check clientId, privateKey and fileGuId
        if (empty($clientId) || empty($privateKey) || empty($sourceFileId) || empty($targetFileId)) {
            throw new Exception('Please enter all required parameters');
        } else {
            //Set variables for Viewer
            F3::set('userId', $clientId);
            F3::set('privateKey', $privateKey);
            //###Create Signer, ApiClient and Storage Api objects

            //Create signer object
            $signer = new GroupDocsRequestSigner($privateKey);
            //Create apiClient object
            $apiClient = new APIClient($signer);
            //Create ComparisonApi object
            $CompareApi = new ComparisonApi($apiClient);
            $CompareApi-&gt;setBasePath($basePath);
            //###Make request to ComparisonApi using user id

            //Comparison of documents where: $clientId - user GuId, $sourceFileId - source file Guid in which will be provided compare,
            //$targetFileId - file GuId with wich will compare sourceFile, $callbackUrl - Url which will be executed after compare,

            $info = $CompareApi-&gt;Compare($clientId, $sourceFileId, $targetFileId, $callbackUrl);

            //###Example of handling callback request:
            //  You can handle callback request in separate php file or in the same one. Our service will post JSON data via post request.
            //In PHP you should get raw data like this:
            //     $json = file_get_contents("php://input"); - get callback data
            //     $fp = fopen(__DIR__ . '/../../temp/signature_request_log.txt', 'a'); - open file for data write
            //     fwrite($fp, $json . "\r\n"); - write data to the file
            //     fclose($fp); - close file

            //Check request status
            if($info-&gt;status == "Ok") {
                //Create AsyncApi object
                $asyncApi = new AsyncApi($apiClient);
                $asyncApi-&gt;setBasePath($basePath);
                //### Check job status

                for ($i = 0; $i &lt;= 5; $i++) {
                    //Delay necessary that the inquiry would manage to be processed
                    sleep(5);
                    //Make request to api for get document info by job id
                    $jobInfo = $asyncApi-&gt;GetJobDocuments($clientId, $info-&gt;result-&gt;job_id);
                    //Check job status, if status is Completed or Archived exit from cycle
                    if ($jobInfo-&gt;result-&gt;job_status == "Completed" || $jobInfo-&gt;result-&gt;job_status == "Archived") {
                        break;
                    //If job status Postponed throw exception with error
                    } elseif ($jobInfo-&gt;result-&gt;job_status == "Postponed") {
                        throw new Exception('Job is failure');
                    }

                }
                //Get file guid
                $guid = $jobInfo-&gt;result-&gt;outputs[0]-&gt;guid;
                // Construct iframe using fileId
                if($basePath == "https://api.groupdocs.com/v2.0") {
                    $iframe = 'https://apps.groupdocs.com/document-viewer/embed/' . $guid . ' frameborder="0" width="800" height="650"';
                //iframe to dev server
                } elseif($basePath == "https://dev-api.groupdocs.com/v2.0") {
                    $iframe = 'https://dev-apps.groupdocs.com/document-viewer/embed/' . $guid . ' frameborder="0" width="500" height="650"';
                //iframe to test server
                } elseif($basePath == "https://stage-api.groupdocs.com/v2.0") {
                    $iframe = 'https://stage-apps.groupdocs.com/document-viewer/embed/' . $guid . ' frameborder="0" width="500" height="650"';
                }

            }
            //If request was successfull - set url variable for template
            return F3::set('iframe', $iframe);
        }
    }

    try {
         Compare($clientId, $privateKey, $sourceFileId, $targetFileId, $callbackUrl, $basePath);

    } catch(Exception $e) {
        $error = 'ERROR: ' .  $e-&gt;getMessage() . "\n";
        f3::set('error', $error);
    }
    //Process template
    f3::set('sourceFileId', $sourceFileId);
    f3::set('targetFileId', $targetFileId);
    f3::set('callbackURL', $callbackUrl);
//    f3::set('result', $result);
    echo Template::serve('comparison.htm');</pre><p></p>
<h3>The Controller Code Explained</h3>
<p>Now the code explanation:</p>
<p>First of all we must get a posted data from form. In Fatfree framework we can do it with this code:</p><pre class="crayon-plain-tag">$clientId = F3::get('POST["client_id"]');
    $privateKey = F3::get('POST["private_key"]');
    $sourceFileId = f3::get('POST["sourceFileId"]');
    $targetFileId = f3::get('POST["targetFileId"]');
    $callbackUrl = f3::get('POST["callbackUrl"]');
    $basePath = f3::get('POST["server_type"]');</pre><p><tt>F3::get</tt> is a framework method to call to the global associative array of variables passed to the current script via the HTTP POST method.</p>
<p>Now we can declare empty variables for template.</p><pre class="crayon-plain-tag">F3::set('userId', '');
    F3::set('privateKey', '');
    f3::set('result', "");</pre><p><tt>f3::set</tt> is one more framework method similar to <tt>f3::get</tt> but it transfers data to the template. The first parameter is a name of a variable in the template. The second parameter is the data that associated with this variable. Right now, it's a empty string.</p>
<h4>Creating the Compare Function</h4>
<p>Let's create a function named <tt>Compare</tt> which takes the entered data and runs a comparison. First, what this function does is to check that all data has been entered by the user:</p><pre class="crayon-plain-tag">function Compare($clientId, $privateKey, $sourceFileId, $targetFileId, $callbackUrl, $basePath)
    {
       if (empty($clientId) || empty($privateKey) || empty($sourceFileId) || empty($targetFileId)) {
            throw new Exception('Please enter all required parameters');</pre><p>The checks are standard checks for empty values.</p>
<p>If the user entered all the required data, the controller continues its operation:</p><pre class="crayon-plain-tag">} else {
            //Set variables for Viewer
            F3::set('userId', $clientId);
            F3::set('privateKey', $privateKey);
            //###Create Signer, ApiClient and Storage Api objects

            //Create signer object
            $signer = new GroupDocsRequestSigner($privateKey);
            //Create apiClient object
            $apiClient = new APIClient($signer);
            //Create ComparisonApi object
            $CompareApi = new ComparisonApi($apiClient);</pre><p>This block sets data to the template variables <tt>userId</tt> and <tt>privateKey</tt>, which was empty. After that they contain user entered data.</p>
<p>Next create the <tt>Signer</tt>, <tt>ApiClient</tt> and <tt>Comparison</tt> API objects for making request to the server.</p>
<h4>The Comparison</h4>
<p>And now the comparison magic:</p><pre class="crayon-plain-tag">//Comparison of documents where: $clientId - user GuId, $sourceFileId - source file Guid in which will be provided compare,
            //$targetFileId - file GuId with wich will compare sourceFile, $callbackUrl - Url which will be executed after compare,

            $info = $CompareApi-&gt;Compare($clientId, $sourceFileId, $targetFileId, $callbackUrl);</pre><p>Expected the comparison segment to be bigger? Sorry if you're disappointed. The document comparison is only one line of code: all you need to do is call the <tt>Compare</tt> method from the PHP SDK and transfer the proper data to it. Data such as the client ID (user id), the GUIDs for the two files that will be compared (the source and target file IDs) and, finally, the callback URL which can be an empty string.</p>
<p>The next step is a check of the comparison results:</p><pre class="crayon-plain-tag">if($info-&gt;status == "Ok") {
                //Create AsyncApi object
                $asyncApi = new AsyncApi($apiClient);

                //### Check job status

                for ($i = 0; $i &lt;= 5; $i++) {
                    //Delay necessary that the inquiry would manage to be processed
                    sleep(5);
                    //Make request to api for get document info by job id
                    $jobInfo = $asyncApi-&gt;GetJobDocuments($clientId, $info-&gt;result-&gt;job_id);
                    //Check job status, if status is Completed or Archived exit from cycle
                    if ($jobInfo-&gt;result-&gt;job_status == "Completed" || $jobInfo-&gt;result-&gt;job_status == "Archived") {
                        break;
                    //If job status Postponed throw exception with error
                    } elseif ($jobInfo-&gt;result-&gt;job_status == "Postponed") {
                        throw new Exception('Job is failure');
                    }

                }
                //Get file guid
                $guid = $jobInfo-&gt;result-&gt;outputs[0]-&gt;guid;
                // Construct iframe using fileId
                $iframe = 'https://apps.groupdocs.com/document-viewer/embed/' . $guid . ' frameborder="0" width="800" height="650"';

            }</pre><p>Here we check what status of request was returned.</p>
<p>If it's "Ok", we can continue and get all the necessary data for an iframe, such as result file GUID, from the returned job ID.</p>
<p>In the server response of the <tt>Compare</tt> method, we have only the request status and job ID which is why we must create an <tt>AsyncApi</tt> object (<tt>$asyncApi = new AsyncApi($apiClient);</tt> and call the <tt>GetJobDocuments</tt> method from this object. This method uses the job ID to get all the info of this job.</p>
<p>Now we must check the job status from <tt>$jobInfo-&gt;result</tt>. If it is "Completed" or "Archived", all is well and we continue. But before we do this check we must allow the server to fulfill the inquiry having established a delay in 5 sec: <tt>sleep(5);</tt>.</p>
<p>After job status check, we can get the result file GUID. It will be in the outputs array: <tt>$guid = $jobInfo-&gt;result-&gt;outputs[0]-&gt;guid;</tt>.</p>
<p>So now we have real file GUID and we can generate an iframe: <tt>$iframe = 'https:**//apps.groupdocs.com/document-viewer/embed/' . $guid . ' frameborder="0" width="800" height="650"';</tt></p>
<h4>Calling the Function</h4>
<p>And one last code block:</p><pre class="crayon-plain-tag">try {
         Compare($clientId, $privateKey, $sourceFileId, $targetFileId, $callbackUrl, $basePath);

    } catch(Exception $e) {
        $error = 'ERROR: ' .  $e-&gt;getMessage() . "\n";
        f3::set('error', $error);
    }
    //Process template
    f3::set('sourceFileId', $sourceFileId);
    f3::set('targetFileId', $targetFileId);
    f3::set('callbackURL', $callbackUrl);
//    f3::set('result', $result);
    echo Template::serve('comparison.htm');</pre><p>In this block we call our function with user data and a catch exception (in case there is an exception). The exception contains all possible errors. And we can set variables for the template and send them to it: <tt>f3::set('sourceFileId', $sourceFileId);</tt>.</p>
<p>As I've already mentioned, this sets variables for the template and this line of code, <tt>echo Template::serve('comparison.htm');</tt> calls template and send data to it.</p>
<p>The iframe, complete with results, looks like this:</p>
<p><a href="http://groupdocs.com/blog/wp-content/uploads/2013/04/iframe1.png"><img class="alignnone size-full wp-image-1861" title="iframe" src="http://groupdocs.com/blog/wp-content/uploads/2013/04/iframe1.png" alt="iframe1 How to Compare Files with GroupDocs PHP SDK"  /></a></p>
<p>With this, I am finished. That is all. Peace.</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
<p>&nbsp;</p>
]]></content:encoded>
			<wfw:commentRss>http://groupdocs.com/blog/how-to-compare-files-with-groupdocs-php-sdk/feed</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>

<!-- Performance optimized by W3 Total Cache. Learn more: http://www.w3-edge.com/wordpress-plugins/

Page Caching using disk: basic

 Served from: localhost @ 2013-05-21 16:34:56 by W3 Total Cache -->