<?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>Linden LAN &#187; PHP</title>
	<atom:link href="http://www.lindenlan.net/tag/php/feed/" rel="self" type="application/rss+xml" />
	<link>http://www.lindenlan.net</link>
	<description></description>
	<lastBuildDate>Sat, 29 Nov 2014 04:54:20 +0000</lastBuildDate>
	<language>en-US</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	
	<item>
		<title>Hyphenation!</title>
		<link>http://www.lindenlan.net/2009/11/13/hyphenation/</link>
		<comments>http://www.lindenlan.net/2009/11/13/hyphenation/#comments</comments>
		<pubDate>Sat, 14 Nov 2009 05:04:43 +0000</pubDate>
		<dc:creator><![CDATA[Admin]]></dc:creator>
				<category><![CDATA[Software]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/?p=357</guid>
		<description><![CDATA[Do you like typography? Are you tired of ragged right text? Do you have a WordPress blog? Go here now! wp-Typography is the merger of wp-Typogrify and, more importantly, wp-Hyphenate. I do LaTeX typesetting, and as a result, I’ve acquired an appreciation for properly formatted text. If you ever tried using the CSS property text-align, [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Do you like typography?  Are you tired of ragged right text?  Do you have a WordPress blog?  Go <a href="http://kingdesk.com/projects/wp-typography/">here</a> now!  wp-Typography is the merger of wp-Typogrify and, more importantly, wp-Hyphenate.  I do LaTeX typesetting, and as a result, I’ve acquired an appreciation for properly formatted text.  If you ever tried using the CSS property <code>text-align</code>, you inevitably are disappointed with the results because it resembles nothing like what LaTeX can produce.  You often have to make your text eye-jarringly wide to make it useable, and that doesn’t always work.   This is because the browser lacks built-in support for hyphenation.  This plugin makes up for this browser deficiency by inserting hyphenation hints, known as soft-hyphens, which the browser does understand.  The algorithm is based on the one used in TeX to boot!  Brilliant!   </p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2009/11/13/hyphenation/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>How To Simultaneously Add Multiple Products To A Magento Shopping Cart</title>
		<link>http://www.lindenlan.net/2009/09/27/how-to-simultaneously-add-multiple-products-to-a-magento-shopping-cart/</link>
		<comments>http://www.lindenlan.net/2009/09/27/how-to-simultaneously-add-multiple-products-to-a-magento-shopping-cart/#comments</comments>
		<pubDate>Mon, 28 Sep 2009 02:01:38 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/?p=349</guid>
		<description><![CDATA[This post is a bit overdue considering the project for which I did this was completed months ago. I finally got around to documenting it. Magento’s product list view lets customers add products to the shopping cart one at a time. The client wanted customers to be able to add multiple products to the shopping [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>This post is a bit overdue considering the project for which I did this was completed months ago.  I finally got around to documenting it.  Magento’s product list view lets customers add products to the shopping cart one at a time.  The client wanted customers to be able to add multiple products to the shopping cart simultaneously.  Given the time constraints for the projects, I created an ad hoc AJAX method to accomplish this feature request.</p>
<p><span id="more-349"></span></p>
<p>Adding a product to a Magento (ver. 1.3.1) shopping cart is accomplished through an HTTP GET request.  It will look like or similar to this:</p>
<pre class="brush: sh">
/path/to/app/checkout/cart/add?product=[id]&amp;qty=[qty]
</pre>
<p>That URL is output by the template helper:</p>
<pre class="brush: php">
$this-&gt;getAddToCartUrl($_product)
</pre>
<p>Since adding a product to the shopping cart is nothing more than a GET request, then all that needs to be done is queue up the URLs of the desired products, make each request in order, and then reload the page when done.</p>
<p>First, in app/design/frontend/
<package>/
<theme>/template/catalog/product/list.html, I first added checkboxes to allow customers to select which products they want and also hidden fields for storing the URLs to add the product and text fields for the quantity. </p>
<pre class="brush: php">
&lt;input type=&quot;checkbox&quot; class=&quot;input-checkbox add&quot; name=&quot;add_&lt;?php echo $_iterator; ?&gt;&quot; id=&quot;add_&lt;?php echo $_iterator; ?&gt;&quot; /&gt;
&lt;input type=&quot;hidden&quot; name=&quot;url_&lt;?php echo $_iterator; ?&gt;&quot; id=&quot;url_&lt;?php echo $_iterator; ?&gt;&quot; value=&quot;&lt;?php echo $this-&gt;getAddToCartUrl($_product) ?&gt;&quot; /&gt;
&lt;?php if(!$_product-&gt;isGrouped()): ?&gt;
     &lt;input type=&quot;text&quot; class=&quot;input-text qty&quot; name=&quot;qty_&lt;?php echo $_iterator; ?&gt;&quot; id=&quot;qty_&lt;?php echo $_iterator; ?&gt;&quot; maxlength=&quot;12&quot; value=&quot;&lt;?php echo $this-&gt;getMinimalQty($_product) ?&gt;&quot; /&gt;
&lt;?php endif; ?&gt;
</pre>
<p>I added this code within the loop that generate the HTML for the product line items for the list.  Next, I added the JavaScript that does the actual processing, also within the list section right after the script block that contains: <code>decorateList('products-list', 'none-recursive')</code>.</p>
<pre class="brush: javascript">
&lt;script type=&quot;text/javascript&quot;&gt;
    function processNext(urls, i) {
        var next = i + 1;
        $(&#039;processing-text&#039;).update(&#039;Processing item &#039; + next);
        if (next &lt; urls.size()) {
            new Ajax.Request(urls[i], {
              method: &#039;get&#039;,
              onComplete: function(transport) {
                processNext(urls, next);
              }
            });
        } else {
            new Ajax.Request(urls[i], {
              method: &#039;get&#039;,
              onComplete: function(transport) {
                window.location.reload();
              }
            });
        }
    }

    function addItemsToCart() {
        $(&#039;add-items-to-cart&#039;).hide();
        $(&#039;waiting&#039;).show();
        
        var addToCartUrls = [];
        $$(&#039;input.add&#039;).each(function(e){ 
            if(e.checked == true) {
                var id = e.readAttribute(&#039;id&#039;).split(&#039;_&#039;)[1];
                var qty = Number($(&#039;qty_&#039; + id).value);
                if (qty &lt; 1) qty = 1;
                addToCartUrls.push($(&#039;url_&#039; + id).value + &#039;qty/&#039; + qty);
            }
        });
        
        if (addToCartUrls.size() &gt; 0) {
            processNext(addToCartUrls, 0);
        } else {
            $(&#039;add-items-to-cart&#039;).show();
            $(&#039;waiting&#039;).hide();
            alert(&#039;Please check off the items you want to add.&#039;);
        }
    }
&lt;/script&gt;
</pre>
<p>At the bottom of the list I added a submit button.</p>
<pre class="brush: php">
&lt;div style=&quot;margin-bottom:5px; text-align:right;&quot;&gt;&lt;button id=&quot;add-items-to-cart&quot; class=&quot;form-button&quot; onclick=&quot;addItemsToCart()&quot;&gt;&lt;span&gt;&lt;?php echo $this-&gt;__(&#039;Add Items to Cart&#039;) ?&gt;&lt;/span&gt;&lt;/button&gt;&lt;div id=&quot;waiting&quot; style=&quot;height:22px; display:none; line-height:22px;&quot;&gt;&lt;span id=&quot;processing-text&quot;&gt;Processing...&lt;/span&gt; &lt;img src=&quot;&lt;?php echo $this-&gt;getSkinUrl().&#039;images/wait22trans.gif&#039;; ?&gt;&quot; width=&quot;22&quot; height=&quot;22&quot; style=&quot;display:inline; vertical-align:middle;&quot;/&gt;&lt;/div&gt;&lt;/div&gt;
</pre>
<p>Clicking the button calls the function <code>addItemsToCart()</code>.  The function hides the button to prevent a double click and unhides the status message.  Next, the function determines which checkboxes are checked.  For each checked checkbox, the function finds the corresponding URL field and quantity field, concatenates the two values, and stores the new URL in an array.  If the length of the array is greater than 0, then the function calls <code>processNext()</code>, otherwise it displays an error message and resets the submit button.</p>
<p>The function <code>processNext()</code> first updates the processing message.  The function takes the array of URLs and an index, and then creates an AJAX GET request using the URL at the given index in the array.  If the AJAX request completes, it calls processNext() with the same array but with an incremented index while the index is less than the array length.  If the incremented index is greater than the array length, then that ends the processing and the function reloads the page.</p>
<p>That’s it.  If there is anything wrong with the code, it assumes that all the GET requests will complete.  Unfortunately, given the time constraints there was no time to account for the scenario where a GET request fails.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2009/09/27/how-to-simultaneously-add-multiple-products-to-a-magento-shopping-cart/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>MyGoogleCal is now RESTYLEgc</title>
		<link>http://www.lindenlan.net/2009/07/06/mygooglecal-is-now-restylegc/</link>
		<comments>http://www.lindenlan.net/2009/07/06/mygooglecal-is-now-restylegc/#comments</comments>
		<pubDate>Mon, 06 Jul 2009 16:24:40 +0000</pubDate>
		<dc:creator><![CDATA[Admin]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Hacking]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>
		<category><![CDATA[RESTYLEgc]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/?p=323</guid>
		<description><![CDATA[I finally got around to spinning off MyGoogleCal as a separate website. I opted to rename the script to RESTYLEgc to avoid stepping on Google’s toes. It was something that’s been gestating over the past year. I completed the site over the holiday weekend since I had the time available. The new site is at [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>I finally got around to spinning off MyGoogleCal as a separate website.  I opted to rename the script to RESTYLEgc to avoid stepping on Google’s toes.  It was something that’s been gestating over the past year.  I completed the site over the holiday weekend since I had the time available.  The new site is at <a href="http://www.restylegc.com/">www.restylegc.com</a>.  I’m also hosting the script at <a href="http://code.google.com/p/restylegc">Google Code</a>, and I even added a <a href="http://groups.google.com/group/RESTYLEgc">Google Group</a> to facilitate discussions.  After seeing the comments top 100, I realize a blog really isn’t suitable for lengthy discussions.  Hopefully, the forum and wiki features will be better for the end-user.</p>
<p>I updated MyGoogleCal4 with a small bugfix this weekend as well.  That will be the last update.  Future development will continue with RESTYLEgc.  Since the code was originally public domain, I opted to go with an MIT open source license.  I also got the code in a Subversion repository which I should’ve done a long time ago.  With the Issues tab at Google Code, I can better track and encourage bug reports and feature requests.</p>
<p>The code is still free, but paid support is available.  I’ve also got some other ideas of where I want to take the site.  So stay tuned!</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2009/07/06/mygooglecal-is-now-restylegc/feed/</wfw:commentRss>
		<slash:comments>4</slash:comments>
		</item>
		<item>
		<title>How To Fake a Magento Subpage</title>
		<link>http://www.lindenlan.net/2009/04/21/how-to-fake-a-magento-subpage/</link>
		<comments>http://www.lindenlan.net/2009/04/21/how-to-fake-a-magento-subpage/#comments</comments>
		<pubDate>Tue, 21 Apr 2009 14:52:50 +0000</pubDate>
		<dc:creator><![CDATA[Admin]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Magento]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/?p=308</guid>
		<description><![CDATA[Magento, an open-source PHP ecommerce solution, has a very comprehensive feature list. However, its built-in CMS doesn’t support hierarchical pages. You can fake it, though. Let’s say you have a page with an SEF (search engine friendly) URL Identifier of “foo”. You’d like to have a subpage “bar” nested under foo. The CMS doesn’t let [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>Magento, an open-source PHP ecommerce solution, has a very comprehensive feature list.  However, its built-in CMS doesn’t support hierarchical pages.  You can fake it, though.  </p>
<p><span id="more-308"></span></p>
<p>Let’s say you have a page with an SEF (search engine friendly) URL Identifier of “foo”.  You’d like to have a subpage “bar” nested under foo.  The CMS doesn’t let you create parent-child relationships, but Magento will let you include forward slashes in the SEF URL Identifier so that it is “foo/bar”.  </p>
<p>That’s the good news.  The bad news is if you want to use the breadcrumbs block, it won’t work out of the box.  The Magento CMS is flat, so the default breadcrumbs will always look like “Home / My Page Title.”  The optimal solution is to override the breadcrumbs module and parse the SEF URL Identifier and construct the breadcrumbs from that.  (I may write a post about it in the future so stay tuned.)  The good news for those designers out there, you don’t have to dive into code.  </p>
<p>Magento’s CMS has a feature where each page has a way to override its XML layout.  When you’re editing a page, go to the “Custom Design” tab.  There you’ll see a form field called “Layout Update XML”.  This is the key.  Here’s where you add XML to first unset the breadcrumbs block and then add it back in but with your specific breadcrumbs.  Here’s the code:</p>
<pre class="brush: html">
&lt;reference name=&quot;root&quot;&gt;
&lt;action method=&quot;unsetChild&quot;&gt;&lt;alias&gt;breadcrumbs&lt;/alias&gt;&lt;/action&gt;
&lt;/reference&gt;

&lt;reference name=&quot;root&quot;&gt;
&lt;block type=&quot;page/html_breadcrumbs&quot; name=&quot;breadcrumbs&quot; as=&quot;breadcrumbs&quot;&gt;
    &lt;action method=&quot;addCrumb&quot;&gt;
        &lt;crumbName&gt;home&lt;/crumbName&gt;
        &lt;crumbInfo&gt;&lt;label&gt;Home&lt;/label&gt;&lt;title&gt;Go to Home Page&lt;/title&gt;&lt;link&gt;/&lt;/link&gt;&lt;/crumbInfo&gt;
    &lt;/action&gt;             
    &lt;action method=&quot;addCrumb&quot;&gt;
        &lt;crumbName&gt;foo&lt;/crumbName&gt;
        &lt;crumbInfo&gt;&lt;label&gt;Foo&lt;/label&gt;&lt;title&gt;Foo&lt;/title&gt;&lt;link&gt;/foo/&lt;/link&gt;&lt;/crumbInfo&gt;
    &lt;/action&gt;             
    &lt;action method=&quot;addCrumb&quot;&gt;
        &lt;crumbName&gt;cms_page&lt;/crumbName&gt;
        &lt;crumbInfo&gt;&lt;label&gt;Bar&lt;/label&gt;&lt;title&gt;Bar&lt;/title&gt;&lt;/crumbInfo&gt;
    &lt;/action&gt;                  
&lt;/block&gt;
&lt;/reference&gt;
</pre>
<p>The first reference tells Magento to call the unset action on the root block to remove the original breadcrumbs.  The second reference tells Magento to add a new breadcrumbs block.  Then within that block it tells Magento to add three new breadcrumbs, one for “home”, one for “foo”, and another for “bar”.  crumbName is just a unique identifier.  Under crumbInfo, label is the link text, title is the hover text, and link is the URL.  You need to include the root forward slash.  The trailing slash is optional, but to be consistent with Magento you should include it.</p>
<p>And that’s all there is to it.  If you have a Magento site with lots of CMS subpages or pages that are deeply nested, then this method can get tedious.  That’s why I said the optimal solution is to override the breadcrumbs module in core as a local modification.  If you don’t have many CMS subpages and they’re only one-level deep, then this method is adequate.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2009/04/21/how-to-fake-a-magento-subpage/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>It’s Tax(onomy) Season</title>
		<link>http://www.lindenlan.net/2009/03/10/its-taxonomy-season/</link>
		<comments>http://www.lindenlan.net/2009/03/10/its-taxonomy-season/#comments</comments>
		<pubDate>Tue, 10 Mar 2009 16:51:33 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Drupal]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/?p=298</guid>
		<description><![CDATA[Drupal has a Taxonomy module for categorizing content. The module can generate a select box based on the defined taxonomy. However, it does not support option groups. I figured I’d share my modification for those who’d like to do the same. It was based on code from a Drupal forum post which I think was [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><a href="http://drupal.org/">Drupal</a> has a <a href="http://drupal.org/node/299">Taxonomy</a> module for categorizing content.  The module can generate a select box based on the defined taxonomy.  However, it does not support option groups.  I figured I’d share my modification for those who’d like to do the same.  It was based on code from <a href="http://drupal.org/node/76500">a Drupal forum post</a> which I think was based on Drupal 5, not 6.</p>
<p><span id="more-298"></span></p>
<p>The code that needs to be modified is from _taxonomy_term_select() in modules/taxonomy/taxonomy.module, after line 1032.</p>
<pre class="brush: php">
function _taxonomy_term_select($title, $name, $value, $vocabulary_id, $description, $multiple, $blank, $exclude = array()) {
  $tree = taxonomy_get_tree($vocabulary_id);
  $options = array();

  if ($blank) {
    $options[&#039;&#039;] = $blank;
  }
  if ($tree) {
    $curr_group = &#039;&#039;;
    foreach ($tree as $term) {
      if (!in_array($term-&gt;tid, $exclude)) {
        if($term-&gt;parents[0] == 0) {
          $curr_group=$term-&gt;name;
          $options[$curr_group] = array();        
        }
        else {
          $choice = new stdClass();
          $choice-&gt;option = array($term-&gt;tid =&gt; str_repeat(&#039;-&#039;, $term-&gt;depth) . $term-&gt;name);
          $options[$curr_group][] = $choice;
        }
      }
    }
  }

  return array(&#039;#type&#039; =&gt; &#039;select&#039;,
    &#039;#title&#039; =&gt; $title,
    &#039;#default_value&#039; =&gt; $value,
    &#039;#options&#039; =&gt; $options,
    &#039;#description&#039; =&gt; $description,
    &#039;#multiple&#039; =&gt; $multiple,
    &#039;#size&#039; =&gt; $multiple ? min(9, count($options)) : 0,
    &#039;#weight&#039; =&gt; -15,
    &#039;#theme&#039; =&gt; &#039;taxonomy_term_select&#039;,
  );
}
</pre>
<p>Essentially, the code simply iterates through the tree like the original code, except when it encounters a root node it creates a new key with an array value to contain the individual options, thereby creating an option group using the term’s name as its label.  The code isn’t very flexible since it won’t account for root nodes with no children.  Also it doesn’t account for options with a depth greater than 1, in which case you’d probably want to set a class and disabled attribute to make it look and act like an option group (since option groups can’t be nested).  Such a change would also involve modifying form_select_options() in includes/form.inc since attributes for option tags is not supported.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2009/03/10/its-taxonomy-season/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>No PHP For You!</title>
		<link>http://www.lindenlan.net/2008/12/14/no-php-for-you/</link>
		<comments>http://www.lindenlan.net/2008/12/14/no-php-for-you/#comments</comments>
		<pubDate>Sun, 14 Dec 2008 21:56:49 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></dc:creator>
				<category><![CDATA[Linux]]></category>
		<category><![CDATA[Apache]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/?p=270</guid>
		<description><![CDATA[On Ubuntu 8.10, I ran into a bit of problem. The Apache web server was working fine, but the following commands: sudo apt-get install php5 libapache-mod-php5 sudo /etc/init.d/apache2 restart failed to work after creating a phpinfo.php file in the /var/www/ root folder. Firefox complained, “You have chosen to open phpinfo.php which is a: PHP file.” [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>On Ubuntu 8.10, I ran into a bit of problem.  The Apache web server was working fine, but the following commands:<br/><br/></p>
<pre class="brush: bash">
sudo apt-get install php5 libapache-mod-php5
sudo /etc/init.d/apache2 restart
</pre>
<p>failed to work after creating a phpinfo.php file in the /var/www/ root folder.  Firefox complained, “You have chosen to open phpinfo.php which is a: PHP file.”  Apache was not using the PHP preprocessor for some reason.  A bunch of forum posts and blogs said to edit either /etc/apache2/httpd.conf or /etc/apache2/apache2.conf in order to associate the PHP mime type with the file extension.  That wouldn’t work because I had also installed phpmyadmin which has an apache.conf file that already has an AddType directive.  So, after some digging around, it turns out the module wasn’t even being loaded, even though that’s what you’d expect the package manager to handle when you tell it to install the module.  Any how, to fix the problem, just create symbolic links to the php5.load and php5.conf files in the /etc/apache2/mods-enabled/ folder.</p>
<pre class="brush: bash">
sudo ln -s /etc/apache2/mods-available/php5.load /etc/apache2/mods-enabled/php5.load
sudo ln -s /etc/apache2/mods-available/php5.conf /etc/apache2/mods-enabled/php5.conf
sudo /etc/init.d/apache2 restart
</pre>
<p>Update: Debian-based installs of Apache2 have some handy command line utils for managing the web server.  So to enable a mod, which automates the above, do this instead:</p>
<pre class="brush: bash">
sudo a2enmod php5
</pre>
<p>a2dismod is the command for disabling a mod.  For sites, there is also a2ensite and a2dissite.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2008/12/14/no-php-for-you/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
		<item>
		<title>Restyle Google Calendar 4</title>
		<link>http://www.lindenlan.net/2008/12/04/restyle-google-calendar-4/</link>
		<comments>http://www.lindenlan.net/2008/12/04/restyle-google-calendar-4/#comments</comments>
		<pubDate>Thu, 04 Dec 2008 07:00:55 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Hacking]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/?p=252</guid>
		<description><![CDATA[As a few users of MyGoogleCal3 have already pointed out, the script no longer works properly. That’s the bad news. The good news is version 4 does work. In fact, with the latest changes Google made to their code, ALL the features that were broken in 3 appear to be working now—Agenda/Week view, the calendar [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>As a few users of <a href="http://www.lindenlan.net/2008/04/23/restyle-google-calendar-3/">MyGoogleCal3</a> have already pointed out, the script no longer works properly.  That’s the bad news.  The good news is version 4 does work.  In fact, with the latest changes Google made to their code, ALL the features that were broken in 3 appear to be working now—Agenda/Week view, the calendar navigation buttons, and IE is fixed.   Please download and test out the latest version, and report any bugs in the comments and I’ll try to resolve them as time allows.</p>
<p><span id="more-252"></span><br />
<strong>UPDATE (2009 July 5):</strong> <a href="http://www.lindenlan.net/2009/07/06/mygooglecal-is-now-restylegc/">MyGoogleCal is now RESTYLEgc</a>.</p>
<p><strong>UPDATE (2009 June 23):</strong> Google’s recent update broke the jQuery injection.  In fact, the update is incompatible with injecting jQuery, Prototype, and MooTools.  The only JavaScript framework that works is Dojo.  I updated the code to inject that framework instead.  For those people who value stability over having the latest and greatest features, I also added a comment to MyGoogleCal4js.php that explains how to freeze the calendar version.  That should hopefully help all you fellow developers who tire of your clients calling you when their calendar breaks.</p>
<p><strong>UPDATE (2009 May 3):</strong> <span style="text-decoration: line-through;">MyGoogleCal4 now supports jQuery manipulation of the DOM.</span>  This gives the ability to apply styles after page load.  As an example, the default code removes the inline style on the body tag allowing the stylesheet to set the background color.  The default code also removes the width property from the inline style of the bubble class so that its width can be set in the stylesheet as well.  This should help overcome many of the problems that can’t be solved directly using a stylesheet.  You can thank <a href="http://techtriad.com/">TechTriad.com</a> for funding this new feature.</p>
<p>Download: <a href='http://www.lindenlan.net/wp-content/uploads/2008/12/mygooglecal4.zip'>mygooglecal4.zip</a>.  Contains MyGoogleCal4.php, MyGoogleCal4js.php, mygooglecal4.css, and images.  The CSS file is not guaranteed to be up-to-date so you may have to follow the instructions described in the PHP file to download the latest version from Google.  phpinfo.php is used for diagnostic purposes to make sure your PHP installation is working and that it has the required plugins.  In the archive folder, you can find previous versions of Google’s Javascript and CSS files, in case you want to use those (see MyGoogleCal4js.php).</p>
<pre class="brush: php">
&lt;?php
/*******************************************************************************
 * FILE: MyGoogleCal4.php
 *
 * DESCRIPTION:
 *  This script is an intermediary between an iframe and Google Calendar that
 *  allows you to override the default style.
 *
 * USAGE:
 *  &lt;iframe src=&quot;MyGoogleCal4.php?src=user%40domain.tld&quot;&gt;&lt;/iframe&gt;
 *
 *  where user@domain.tld is a valid Google Calendar account.
 *
 * VALID QUERY STRING PARAMETERS:
 *    title:         any valid url encoded string 
 *                   if not present, takes title from first src
 *    showTitle:     0 or 1 (default)
 *    showNav:       0 or 1 (default)
 *    showDate:      0 or 1 (default)
 *    showTabs:      0 or 1 (default)
 *    showCalendars: 0 or 1 (default)
 *    mode:          WEEK, MONTH (default), AGENDA
 *    height:        a positive integer (should be same height as iframe)
 *    wkst:          1 (Sun; default), 2 (Mon), or 7 (Sat)
 *    hl:            en, zh_TW, zh_CN, da, nl, en_GB, fi, fr, de, it, ja, ko, 
 *                   no, pl, pt_BR, ru, es, sv, tr
 *                   if not present, takes language from first src
 *    bgcolor:       url encoded hex color value, #FFFFFF (default)
 *    src:           url encoded Google Calendar account (required)
 *    color:         url encoded hex color value     
 *                   must immediately follow src
 *    
 *    The query string can contain multiple src/color pairs.  It&#039;s recommended 
 *    to have these pairs of query string parameters at the end of the query 
 *    string.
 *
 * HISTORY:
 *   03 December 2008 - Original release
 *                      Uses technique from MyGoogleCal2 for all browsers,
 *                      rather than giving IE special treatment.
 *   16 December 2008 - Modified MyGoogleCal4js.php so that the regex does a
 *                      general match rather than specifically look for the
 *                      variable &#039;Ac&#039;.
 *   Mar--Apr    2009 - Added jQuery for modifying the style after page load
 *   23 June     2009 - Replaced jQuery with Dojo since jQuery, Prototype, and
 *                      MooTools are not compatible
 *   05 July     2009 - Fixed bug to remove width style from bubble
 *                      
 *   
 * ACKNOWLEDGMENTS:
 *   Michael McCall (http://www.castlemccall.com/) for pointing out &quot;htmlembed&quot;
 *   Mike (http://mikahn.com/) for the link to the online CSS formatter
 *   TechTriad.com (http://techtriad.com/) for requesting and funding the 
 *       Javascript code to edit CSS properties and for selflessly letting the
 *       code be published for everyone&#039;s use and benefit.
 *   
 *
 * copyright (c) by Brian Gibson
 * email: bwg1974 yahoo com
 ******************************************************************************/

/* URL for overriding stylesheet
 * The best way to create this stylesheet is to 
 * 1) Load &quot;http://www.google.com/calendar/embed?src=user%40domain.tld&quot; in a
 *    browser,
 * 2) View the source (e.g., View-&gt;Page Source in Firefox),
 * 3) Copy the relative URL of the stylesheet (i.e., the href value of the 
 *    &lt;link&gt; tag), 
 * 4) Load the stylesheet in the browser by pasting the stylesheet URL into 
 *    the address bar so that it reads similar to:
 *    &quot;http://www.google.com/calendar/d003e2eff7c42eebf779ecbd527f1fe0embedcompiled.css&quot;
 * 5) Save the stylesheet (e.g., File-&gt;Save Page As in Firefox)
 * Edit this new file to change the style of the calendar.
 *
 * As an alternative method, take the URL you copied in Step 3, and paste it
 * in the URL field at http://mabblog.com/cssoptimizer/uncompress.html.
 * That site will automatically format the CSS so that it&#039;s easier to edit.
 */
$stylesheet = &#039;mygooglecal4.css&#039;;

/*******************************************************************************
 * DO NOT EDIT BELOW UNLESS YOU KNOW WHAT YOU&#039;RE DOING
 ******************************************************************************/

// URL for the calendar
$url = &quot;&quot;;
if(count($_GET) &gt; 0) {
  $url = &quot;http://www.google.com/calendar/embed?&quot; . $_SERVER[&#039;QUERY_STRING&#039;];
}

// Request the calendar
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$buffer = curl_exec($ch);
curl_close($ch);

// Point stylesheet and javascript to custom versions
$pattern = &#039;/(&lt;link.*&gt;)/&#039;;
$replacement = &#039;&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;&#039; . $stylesheet . &#039;&quot; /&gt;&#039;;
$buffer = preg_replace($pattern, $replacement, $buffer);

$pattern = &#039;/src=&quot;(.*js)&quot;/&#039;;
$replacement = &#039;src=&quot;MyGoogleCal4js.php?$1&quot;&#039;;  
$buffer = preg_replace($pattern, $replacement, $buffer);

// Add a hook to the window onload function
$pattern = &#039;/}\);}&lt;\/script&gt;/&#039;;
$replacement = &#039;}); myGoogleCal();}&lt;/script&gt;&#039;;
$buffer = preg_replace($pattern, $replacement, $buffer);

// Use DHTML to modify the DOM after the calendar loads
$pattern = &#039;/(&lt;\/head&gt;)/&#039;;
$replacement = &lt;&lt;&lt;MGC
&lt;script type=&quot;text/javascript&quot; src=&quot;http://ajax.googleapis.com/ajax/libs/dojo/1.3.1/dojo/dojo.xd.js&quot;&gt;&lt;/script&gt;
&lt;script type=&quot;text/javascript&quot;&gt;
function myGoogleCal() {
    // remove inline style from body so background-color can be set using the stylesheet
    dojo.removeAttr(dojo.body(),&#039;style&#039;);

    // iterate over each bubble and remove the width property from the style attribute
    // so that the width can be set using the stylesheet
    dojo.query(&#039;.bubble&#039;).forEach(function(node){
        dojo.attr(node, {style:{&#039;width&#039;: &#039;&#039;}});
    });

    // see Dojo documentation for other ways to edit DOM
    // http://dojotoolkit.org/
}
&lt;/script&gt;
&lt;/head&gt;
MGC;
$buffer = preg_replace($pattern, $replacement, $buffer);

// display the calendar
print $buffer;
?&gt;

?&gt;
</pre>
<p>If you look at lines 39–41 in MyGoogleCal4js.php, you’ll see how simple the fix is.  No more XmlHttpRequest bugs.  Thank you, Google.</p>
<pre class="brush: php">
&lt;?php header(&quot;Content-type: application/x-javascript&quot;);
/*******************************************************************************
 * FILE: MyGoogleCal4js.php
 *
 * DESCRIPTION:
 *  Companion file for MyGoogleCal4.php to edit the javascript file that
 *  generates the Google Calendar.
 *   
 * USAGE:
 *  There are no user-editable parameters.
 *
 * copyright (c) by Brian Gibson
 * email: bwg1974 yahoo com
 ******************************************************************************/
// URL for the javascript
$url = &quot;&quot;;
if(count($_GET) &gt; 0) {
  $url = &quot;http://www.google.com/calendar/&quot; . $_SERVER[&#039;QUERY_STRING&#039;];
}

/* If you would like to freeze the calendar version, download the Javascript
 * file using the same method for downloading the CSS file, as described in
 * the main script.  You can find some previous versions in the archive folder.
 * NOTE: You should use the corresponding CSS file as well.
 *
 * Edit and uncomment the following line to freeze the calendar version.
 */
//$url = &quot;http://myserver.tld/path/to/archive/6a3eb8ba4a07edb76f79a18d6bdb8933embedcompiled__en.js&quot;;

// Request the javascript
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$buffer = curl_exec($ch);
curl_close($ch);

// Fix URLs in the javascript
$pattern = &#039;/this\.[a-zA-Z]{2}\+&quot;calendar/&#039;;
$replacement = &#039;&quot;http://www.google.com/calendar&#039;;
$buffer = preg_replace($pattern, $replacement, $buffer);

// Display the javascript
print $buffer;
?&gt;
</pre>
<p>The installation of MyGoogleCal4 is the same as the <a href="http://www.lindenlan.net/2008/03/22/how-to-install-mygooglecal2php/">installation for MyGoogleCal2</a> except you download the zip file above.  You can ignore step 3 regarding the .htaccess file.  As far as I can tell, it’s no longer needed.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2008/12/04/restyle-google-calendar-4/feed/</wfw:commentRss>
		<slash:comments>134</slash:comments>
		</item>
		<item>
		<title>Restyle Google Calendar 3</title>
		<link>http://www.lindenlan.net/2008/04/23/restyle-google-calendar-3/</link>
		<comments>http://www.lindenlan.net/2008/04/23/restyle-google-calendar-3/#comments</comments>
		<pubDate>Thu, 24 Apr 2008 05:46:09 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Hacking]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/2008/04/23/restyle-google-calendar-3/</guid>
		<description><![CDATA[MyGoogleCal2 no longer works 100% in Internet Explorer. A runtime error occurs when navigating month-to-month or when switching to Agenda mode. The workaround is to simply hide the navigation interface. Now, I don’t know if this bug was introduced when Google updated the code last month, or if it’s always been there and I just [&#8230;]]]></description>
				<content:encoded><![CDATA[<p><a href="http://www.lindenlan.net/2007/10/14/restyle-google-calendar-2/">MyGoogleCal2</a> no longer works 100% in Internet Explorer.  A runtime error occurs when navigating month-to-month or when switching to Agenda mode.  The workaround is to simply hide the navigation interface.  Now, I don’t know if this bug was introduced when Google updated the code last month, or if it’s always been there and I just never noticed.  In any case, the runtime error occurs when <code>//"+a.host+"/calendar</code> is replaced by <code>//www.google.com/calendar</code>.  Given the poor debugging available in IE, I didn’t get very far with figuring out why IE breaks.  I suspect that when IE makes an XmlHttpRequest, it’s double checking that the request URL matches up with the server host, or something to that effect.  Since Google obfuscates the Javascript code, it’s just way too hard to try and fix it.  Instead, I’ve opted to create a new version of MyGoogleCal that uses the <a href="http://www.lindenlan.net/2006/10/08/restyle-google-calendar/">original technique</a> for IE but uses the technique from MyGoogleCal2 for all other browsers.</p>
<p><span id="more-57"></span></p>
<p><strong>UPDATE:</strong> MyGoogleCal now has a <a href="http://www.lindenlan.net/2008/12/04/restyle-google-calendar-4/">fourth version</a>.</p>
<p>Download: <a href='http://www.lindenlan.net/wp-content/uploads/2008/04/mygooglecal3.zip' title='MyGoogleCal3 Zip file'>mygooglecal3.zip</a>.  Contains MyGoogleCal3.php, MyGoogleCal3js.php, mygooglecal3.css, mygooglecal3ie.css, and an .htaccess file.  The CSS files are not guaranteed to be up-to-date so you may have to follow the instructions described in the PHP file to download the latest version from Google.</p>
<pre class="brush: php">
&lt;?php
/*******************************************************************************
 * FILE: MyGoogleCal3.php
 *
 * DESCRIPTION:
 *  This script is an intermediary between an iframe and Google Calendar that
 *  allows you to override the default style.
 *
 * USAGE:
 *  &lt;iframe src=&quot;MyGoogleCal3.php?src=user%40domain.tld&quot;&gt;&lt;/iframe&gt;
 *
 *  where user@domain.tld is a valid Google Calendar account.
 *
 * VALID QUERY STRING PARAMETERS:
 *    title:         any valid url encoded string 
 *                   if not present, takes title from first src
 *    showTitle:     0 or 1 (default)
 *    showNav:       0 or 1 (default)
 *    showDate:      0 or 1 (default)
 *    showTabs:      0 or 1 (default)
 *    showCalendars: 0 or 1 (default)
 *    mode:          WEEK, MONTH (default), AGENDA
 *    height:        a positive integer (should be same height as iframe)
 *    wkst:          1 (Sun; default), 2 (Mon), or 7 (Sat)
 *    hl:            en, zh_TW, zh_CN, da, nl, en_GB, fi, fr, de, it, ja, ko, 
 *                   no, pl, pt_BR, ru, es, sv, tr
 *                   if not present, takes language from first src
 *    bgcolor:       url encoded hex color value, #FFFFFF (default)
 *    src:           url encoded Google Calendar account (required)
 *    color:         url encoded hex color value     
 *                   must immediately follow src
 *    
 *    The query string can contain multiple src/color pairs.  It&#039;s recommended 
 *    to have these pairs of query string parameters at the end of the query 
 *    string.
 *
 * HISTORY:
 *   21 June     2008 - Reverted to an older custom JavaScript file
 *   18 May      2008 - Corrected a bunch of typos 
 *   24 April    2008 - Original release
 *                      Uses the technique from MyGoogleCal for IE browsers and
 *                      the technique from MyGoogleCal2 for the rest.
 *   
 * ACKNOWLEDGMENTS:
 *   Michael McCall (http://www.castlemccall.com/) for pointing out &quot;htmlembed&quot;
 *   Mike (http://mikahn.com/) for the link to the online CSS formatter
 *
 * copyright (c) by Brian Gibson
 * email: bwg1974 yahoo com
 ******************************************************************************/

/* URL for overriding stylesheet
 * The best way to create this stylesheet is to 
 * 1) Load &quot;http://www.google.com/calendar/embed?src=user%40domain.tld&quot; in a
 *    browser,
 * 2) View the source (e.g., View-&gt;Page Source in Firefox),
 * 3) Copy the relative URL of the stylesheet (i.e., the href value of the 
 *    &lt;link&gt; tag), 
 * 4) Load the stylesheet in the browser by pasting the stylesheet URL into 
 *    the address bar so that it reads similar to:
 *    &quot;http://www.google.com/calendar/embed/d003e2eff7c42eebf779ecbd527f1fe0embedcompiled.css&quot;
 * 5) Save the stylesheet (e.g., File-&gt;Save Page As in Firefox)
 * Edit this new file to change the style of the calendar.
 *
 * As an alternative method, take the URL you copied in Step 3, and paste it
 * in the URL field at http://mabblog.com/cssoptimizer/uncompress.html.
 * That site will automatically format the CSS so that it&#039;s easier to edit.
 */
$stylesheet = &#039;mygooglecal3.css&#039;;

/* For the IE stylesheet replace &quot;embed&quot; with &quot;htmlembed&quot; in step (1) 
 */
$stylesheet_ie = &#039;mygooglecal3ie.css&#039;;

/*******************************************************************************
 * DO NOT EDIT BELOW UNLESS YOU KNOW WHAT YOU&#039;RE DOING
 ******************************************************************************/

// URL for the calendar
$url = &quot;&quot;;
$is_ie = FALSE;
if(count($_GET) &gt; 0) {
  if(stristr($_SERVER[&#039;HTTP_USER_AGENT&#039;], &#039;msie&#039;) === FALSE) {
    $url = &quot;http://www.google.com/calendar/embed?&quot; . $_SERVER[&#039;QUERY_STRING&#039;];
  } else {
    $url = &quot;http://www.google.com/calendar/htmlembed?&quot; . $_SERVER[&#039;QUERY_STRING&#039;];
    $is_ie = TRUE;
  }
}

// Request the calendar
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$buffer = curl_exec($ch);
curl_close($ch);

if($is_ie) {
  // Fix hrefs, image sources, and stylesheet
  $pattern = &#039;/(href=&quot;render)/&#039;;
  $replacement = &#039;href=&quot;http://www.google.com/calendar/render&#039;;
  $buffer = preg_replace($pattern, $replacement, $buffer);

  $pattern = &#039;/(href=&quot;event)/&#039;;
  $replacement = &#039;href=&quot;http://www.google.com/calendar/event&#039;;
  $buffer = preg_replace($pattern, $replacement, $buffer);

  $pattern = &#039;/(http:\/\/www.google.com\/calendar\/htmlembed)/&#039;;
  $replacement = &#039;MyGoogleCal3.php&#039;;
  $buffer = preg_replace($pattern, $replacement, $buffer);

  $pattern = &#039;/(src=&quot;images)/&#039;;
  $replacement = &#039;src=&quot;http://www.google.com/calendar/images&#039;;
  $buffer = preg_replace($pattern, $replacement, $buffer);

  $pattern = &#039;/(&lt;link.*&gt;)/&#039;;
  $replacement = &#039;&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;&#039; . $stylesheet_ie . &#039;&quot; /&gt;&#039;;
  $buffer = preg_replace($pattern, $replacement, $buffer);
} else {
  // Point stylesheet and javascript to custom versions
  $pattern = &#039;/(&lt;link.*&gt;)/&#039;;
  $replacement = &#039;&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;&#039; . $stylesheet . &#039;&quot; /&gt;&#039;;
  $buffer = preg_replace($pattern, $replacement, $buffer);

  $pattern = &#039;/src=&quot;(.*js)&quot;/&#039;;
  $replacement = &#039;src=&quot;MyGoogleCal3js.php?$1&quot;&#039;;
  $buffer = preg_replace($pattern, $replacement, $buffer);
}

// display the calendar
print $buffer;
?&gt;
</pre>
<p>The installation of MyGoogleCal3 is more or less the same as the <a href="http://www.lindenlan.net/2008/03/22/how-to-install-mygooglecal2php/">installation for MyGoogleCal2</a> except you download the zip file above.  Also MyGoogleCal3 uses two stylesheets, one for IE and one for all the other browsers.</p>
<p>There is a minor bug.  Despite changing the URL from <code>../images/ext/poweredby.png</code> to <code>images/poweredby.png</code> in the IE CSS file, this does not make the Powered by Google logo appear in the lower right.  I think that’s OK since it doesn’t appear on Google’s site either.</p>
<p><strong>Update (21 Jun 2008):</strong> Google changed the JavaScript once again and this time very radically.  I’ve been keeping snapshots of their JavaScript code, so I’ve changed the script to load an older customized .js file.  This is a quick fix.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2008/04/23/restyle-google-calendar-3/feed/</wfw:commentRss>
		<slash:comments>35</slash:comments>
		</item>
		<item>
		<title>How To Install MyGoogleCal2.php</title>
		<link>http://www.lindenlan.net/2008/03/22/how-to-install-mygooglecal2php/</link>
		<comments>http://www.lindenlan.net/2008/03/22/how-to-install-mygooglecal2php/#comments</comments>
		<pubDate>Sun, 23 Mar 2008 05:12:37 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Hacking]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/2008/03/22/how-to-install-mygooglecal2php/</guid>
		<description><![CDATA[One of my readers asked for a step-by-step set of instructions to install MyGoogleCal2.php. My original posts for restyling Google Calendar did assume a certain level of expertise. This should hopefully help those who are still confused. Download mygooglecal2.zip. Unzip the file on your server, typically into a subfolder named ‘mygooglecal’. If your web server [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>One of my readers asked for a step-by-step set of instructions to install <a href="http://www.lindenlan.net/2007/10/14/restyle-google-calendar-2/">MyGoogleCal2.php</a>.  My original posts for restyling Google Calendar did assume a certain level of expertise.  This should hopefully help those who are still confused.</p>
<p><span id="more-54"></span></p>
<ol>
<li>
<p>Download <a href='http://www.lindenlan.net/wp-content/uploads/2007/10/mygooglecal2.zip' title='MyGoogleCal2 zip file'>mygooglecal2.zip</a>.</p>
</li>
<li>
<p>Unzip the file on your server, typically into a subfolder named ‘mygooglecal’.</p>
</li>
<li>
<p>If your web server supports .htaccess files and your site does not already have one, just move the .htaccess file that was in the zip file to the root of your site.  If your web site already has an .htaccess file, then you will need to copy the mod_rewrite rules from the the zip file’s .htaccess file to the existing one.</p>
</li>
<li>
<p>If you have not already done so, go to the <a href="http://www.google.com/calendar/embed/EmbedHelper_en.html">Embeddable Calendar Helper</a> and generate the HTML code for the calendar.  Place this code into the page that will display the calendar.</p>
</li>
<li>
<p>The HTML code for the Google Calendar is an &lt;iframe&gt; tag.  You need to edit the src attribute to point to MyGoogleCal2.php <em>on your server</em> and not http://www.google.com/calendar/embed.  See ‘USAGE:’ in the MyGoogleCal2.php file for an example.</p>
</li>
<li>
<p>That’s the basic installation.  You should be able to edit the included CSS file.  If you want to use a different CSS file or move it somewhere else, make sure to update the $stylesheet variable in MyGoogleCal2.php.  Remember, the CSS file is not guaranteed to be up-to-date so you may have to download your own copy.  Just follow the directions listed in MyGoogleCal2.php.</p>
</li>
</ol>
<p>Some additional notes:</p>
<ul>
<li>
<p>Some of the colors that the Google Calendar uses are: #c3d9ff, #bcd, #cde, #e8eef7, #e5ecf9, and #112abb.  That should help when editing the CSS file.  I highly recommend using Firefox and the <a href="https://addons.mozilla.org/en-US/firefox/addon/1843">Firebug extension</a>.  The extension has an Inspect feature that let’s you select a DOM object and see its element ID, class, and style attributes.  That will help identify which CSS rule you need change.</p>
</li>
<li>
<p>If the display of the calendar is blank, that usually means your PHP configuration is wrong and most likely the curl module is not installed or disabled.  Open the phpinfo.php file included in the zip file.  This will list a bunch of debug information about your web server’s PHP configuration.  If you do not see curl listed or curl is listed but disabled, then you will need to talk to your system administrator to fix it.</p>
</li>
</ul>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2008/03/22/how-to-install-mygooglecal2php/feed/</wfw:commentRss>
		<slash:comments>9</slash:comments>
		</item>
		<item>
		<title>Restyle Google Calendar 2</title>
		<link>http://www.lindenlan.net/2007/10/14/restyle-google-calendar-2/</link>
		<comments>http://www.lindenlan.net/2007/10/14/restyle-google-calendar-2/#comments</comments>
		<pubDate>Mon, 15 Oct 2007 04:38:54 +0000</pubDate>
		<dc:creator><![CDATA[Brian]]></dc:creator>
				<category><![CDATA[Programming]]></category>
		<category><![CDATA[CSS]]></category>
		<category><![CDATA[Google]]></category>
		<category><![CDATA[Hacking]]></category>
		<category><![CDATA[JavaScript]]></category>
		<category><![CDATA[PHP]]></category>

		<guid isPermaLink="false">http://www.lindenlan.net/2007/10/14/restyle-google-calendar-2/</guid>
		<description><![CDATA[The long awaited new version of MyGoogleCal is here. It supports the new AJAX-enabled Javascript method Google switched to last month. As a bonus, the new version has native support for multiple calendars each with their own colors! Other changes to the code include officially switching from fopen to curl to retrieve the data. Furthermore, [&#8230;]]]></description>
				<content:encoded><![CDATA[<p>The long awaited new version of <a href="http://www.lindenlan.net/2006/10/08/restyle-google-calendar/">MyGoogleCal</a> is here.  It supports the new AJAX-enabled Javascript method Google switched to last month.  As a bonus, the new version has native support for multiple calendars each with their own colors!  Other changes to the code include officially switching from fopen to curl to retrieve the data.  Furthermore, the code replaces much less HTML since it’s encapsulated in Javascript.  Without further ado…</p>
<p><span id="more-39"></span></p>
<p><strong>UPDATE:</strong> MyGoogleCal now has a <a href="http://www.lindenlan.net/2008/04/23/restyle-google-calendar-3/">third version</a>.</p>
<p>Download: <a href='http://www.lindenlan.net/wp-content/uploads/2007/10/mygooglecal2.zip' title='mygooglecal2.zip'>mygooglecal2.zip</a>.  Contains MyGoogleCal2.php, mygooglecal2.css, MyGoogleCal2js.php, and an .htaccess file.  The CSS file is not guaranteed to be up-to-date so you may have to follow the instructions described in the PHP file to download the latest version from Google.</p>
<pre class="brush: php">
&lt;?php
/*******************************************************************************
 * FILE: MyGoogleCal2.php
 *
 * DESCRIPTION:
 *  This script is an intermediary between an iframe and Google Calendar that
 *  allows you to override the default style.
 *
 * USAGE:
 *  &lt;iframe src=&quot;MyGoogleCal2.php?src=user%40domain.tld&quot;&gt;&lt;/iframe&gt;
 *
 *  where user@domain.tld is a valid Google Calendar account.
 *
 * VALID QUERY STRING PARAMETERS:
 *    title:         any valid url encoded string 
 *                   if not present, takes title from first src
 *    showTitle:     0 or 1 (default)
 *    showNav:       0 or 1 (default)
 *    showDate:      0 or 1 (default)
 *    showTabs:      0 or 1 (default)
 *    showCalendars: 0 or 1 (default)
 *    mode:          WEEK, MONTH (default), AGENDA
 *    height:        a positive integer (should be same height as iframe)
 *    wkst:          1 (Sun; default), 2 (Mon), or 7 (Sat)
 *    hl:            en, zh_TW, zh_CN, da, nl, en_GB, fi, fr, de, it, ja, ko, 
 *                   no, pl, pt_BR, ru, es, sv, tr
 *                   if not present, takes language from first src
 *    bgcolor:       url encoded hex color value, #FFFFFF (default)
 *    src:           url encoded Google Calendar account (required)
 *    color:         url encoded hex color value     
 *                   must immediately follow src
 *    
 *    The query string can contain multiple src/color pairs.  It&#039;s recommended 
 *    to have these pairs of query string parameters at the end of the query 
 *    string.
 *
 * HISTORY:
 *   22 March    2008 - Replaced the custom javascript with a PHP script that 
 *                      uses the same technique as MyGoogleCal.php
 *   14 March    2008 - Update to match Google changes to javascript code
 *   14 January  2008 - Fixed Add to Calendar URL to point to Google
 *    3 January  2008 - Reverted back to customized javascript code to fix
 *                      bug where no data is displayed when navigating
 *                      into future or past
 *                      Note: imported calendars (e.g. iCal) should work again
 *   29 October  2007 - Update to match Google changes to javascript code
 *                      Note: imported calendars (e.g. iCal) do not work
 *   14 October  2007 - Original release
 *   
 * copyright (c) by Brian Gibson
 * email: bwg1974 yahoo com
 ******************************************************************************/

/* URL for overriding stylesheet
 * The best way to create this stylesheet is to 
 * 1) Load &quot;http://www.google.com/calendar/embed?src=user%40domain.tld&quot; in a
 *    browser,
 * 2) View the source (e.g., View-&gt;Page Source in Firefox),
 * 3) Copy the relative URL of the stylesheet (i.e., the href value of the 
 *    &lt;link&gt; tag), 
 * 4) Load the stylesheet in the browser by pasting the stylesheet URL into 
 *    the address bar so that it reads similar to:
 *    &quot;http://www.google.com/calendar/embed/d003e2eff7c42eebf779ecbd527f1fe0embedcompiled.css&quot;
 * 5) Save the stylesheet (e.g., File-&gt;Save Page As in Firefox)
 * Edit this new file to change the style of the calendar.
 *
 * As an alternative method, take the URL you copied in Step 3, and paste it
 * in the URL field at http://mabblog.com/cssoptimizer/uncompress.html.
 * That site will automatically format the CSS so that&#039;s more easily editable.
 */
$stylesheet = &#039;mygooglecal2.css&#039;;

/*******************************************************************************
 * DO NOT EDIT BELOW UNLESS YOU KNOW WHAT YOU&#039;RE DOING
 ******************************************************************************/

// URL for the calendar
$url = &quot;&quot;;
if(count($_GET) &gt; 0) {
  $url = &quot;http://www.google.com/calendar/embed?&quot; . $_SERVER[&#039;QUERY_STRING&#039;];
}

// Request the calendar
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_HEADER, 0);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
$buffer = curl_exec($ch);
curl_close($ch);

// Point stylesheet and javascript to custom versions
$pattern = &#039;/(&lt;link.*&gt;)/&#039;;
$replacement = &#039;&lt;link rel=&quot;stylesheet&quot; type=&quot;text/css&quot; href=&quot;&#039; . $stylesheet . &#039;&quot; /&gt;&#039;;
$buffer = preg_replace($pattern, $replacement, $buffer);

$pattern = &#039;/src=&quot;(.*js)&quot;/&#039;;
$replacement = &#039;src=&quot;MyGoogleCal2js.php?$1&quot;&#039;;
$buffer = preg_replace($pattern, $replacement, $buffer);

// display the calendar
print $buffer;
?&gt;
</pre>
<p>Use is similar to the original MyGoogleCal.php.  To help create the &lt;iframe&gt;, you can use the <a href="http://www.google.com/calendar/embed/EmbedHelper_en.html">Embeddable Calendar Helper</a>.  Just remember to update the src attribute to point to MyGoogleCal2.php and not http://www.google.com/calendar/embed.  </p>
<p><span style="text-decoration: line-through;">In addition to a custom CSS file the script makes use of a custom Javascript file.  Each URL is set after the script’s header and includes instructions on how to download versions of these files from Google.  This is important since it appears that the Javascript file is localized.  (I included copies that I downloaded in the above Zip file.)</span> </p>
<p><strong>Update (22 Mar 08):</strong> I created a new PHP file, MyGoogleCal2js.php, which downloads the JavaScript code and edits the code on-the-fly.  This negates the need to maintain a customized version of the JavaScript code on the same server as the MyGoogleCal.php script.   This should also lessen the chance that MyGoogleCal2.php will break when Google updates the code as long as the changes are minor.</p>
<p>The UI images are no longer contained in the CSS file.  You have two options on how to handle this.  If your site runs off of Apache, you can create a rewrite rule to hotlink to the Google images.  (I included an .htaccess file in the Zip file above that has a sample rule.)  The other, more conventional option is to create an “images” subfolder where the script is located and place copies of these images there.  You will definitely have to do this if you want to replace those images with customized versions. (I included images in the Zip file.)</p>
<p>What I’m hung-up on right now is figuring out a way to not have to save and rewrite the Javascript file.  The Javascript file is responsible for drawing the calendar, retrieving the XML data from Google, and then putting that data into the calendar.   The <code>_init()</code> function dynamically creates the URL from which to retrieve the XML data by using the browser’s window.location.host property.  Since the browser will presumably be pointing to your site, the host property will not be www.google.com.  As a result, the Javascript <span style="text-decoration: line-through;">hangs at the XML loading stage</span> fails to retrieve data when navigating into the future or past.  My attempts at circumventing this problem has been met with little success.</p>
<p>I tried the passthru directive in .htaccess file like so:</p>
<pre class="brush: xhtml">
RewriteRule ^(calendar/feeds/.*)$ http://www.google.com/$1 [P]
</pre>
<p>The browser spits out a 502 error.    </p>
<p>A redirect, [R] instead of [P], only works half-way.  The XmlHttpRequest goes thru but the data is rejected because it’s considered insecure since you can’t load data retrieved from an external domain.</p>
<p>I also tried ProxyPass/ProxyPassReverse to map</p>
<pre class="brush: xhtml">
/calendar/
</pre>
<p>to</p>
<pre class="brush: xhtml">

http://www.google.com/calendar

</pre>
<p>but it simply results in an error.  I’ll have to consult with my host to figure if the error is the configuration on their end or mine.</p>
<p><strong>Update (03 Jan 08):</strong> <em>After talking with my hosting provider it turns out this error is the fault of my virtual server and it won’t be fixed since they’re retiring the hardware.  I’ve been placed in the queue to migrate my account over to a new (hopefully problem-free) server.  In any case, I’ll definitely revisit this solution after the migration is over and test it then.</em></p>
<p>For more info, checkout: <a href="http://www.xml.com/pub/a/2005/11/09/fixing-ajax-xmlhttprequest-considered-harmful.html">Fixing AJAX: XMLHttpRequest Considered Harmful</a> or <a href="http://developer.yahoo.com/javascript/howto-proxy.html">Use a Web Proxy for Cross-Domain XMLHttpRequest Calls</a>.  The last one has pretty pictures.</p>
<p>Failed experiments include:</p>
<ul>
<li>
<p>Use the Javascript prototype mechanism to somehow override the window.location.host property to return a string of my choosing.</p>
</li>
<li>
<p>Rewrite a request to www.google.com to point to MyGoogleCal2.php so that I could inject code into the calendar page.  I thought this had a lot promise up until the point I realized I couldn’t put an .htaccess file at google.com. This was one of those “Duh!” moments.</p>
</li>
<li>
<p>Manipulate the &lt;iframe&gt; DOM in order to change its document.styleSheets property directly.  Due to security reasons, you can’t modify, let alone read, the DOM properties across different domains.</p>
</li>
<li>
<p>Proxy the XmlHttpRequest thru a curl script.  This almost worked.  The curl request succeeded in getting the JSON data, but for whatever reason, the Javascript code failed to do anything with it.  Depending on the content-type requested for the response, either nothing happening or the browser would spit out a Javascript error.  I’m sure it had to with an incomplete request header or returning just the response data instead of the entire response.  But whatever reason it was, this solution seemed more trouble than it was worth.</p>
</li>
</ul>
<p><span style="text-decoration: line-through;"><strong>Update (29 Oct 07):</strong> <em>Google’s new version of the Javascript code does not require any customization.  Do you suppose some Google developer read my post? <img src="http://www.lindenlan.net/wp-includes/images/smilies/icon_smile.gif" alt=":-)" class="wp-smiley" /> However, a side-effect is that imported calendars do not work.  I’m betting it has to do with XmlHttpRequest permissions, but I won’t know for certain without further investigation.</em></span> </p>
<p>When you’re done restyling your calendar, <a href="http://www.lindenlan.net/2008/01/10/calendar-casting-call/">show it off</a>!  Oh and don’t forget to Digg the article.</p>
]]></content:encoded>
			<wfw:commentRss>http://www.lindenlan.net/2007/10/14/restyle-google-calendar-2/feed/</wfw:commentRss>
		<slash:comments>79</slash:comments>
		</item>
	</channel>
</rss>

<!-- Dynamic page generated in 0.484 seconds. -->
<!-- Cached page generated by WP-Super-Cache on 2026-04-19 00:23:10 -->

<!-- Compression = gzip -->