Saturday, June 9, 2007

Optimal OPML Browser & WordPress Plugin

I've been meaning to put up my reading list on my personal blog (Tome of Wisdom). I needed three things:
  • An easily updateable news aggregator that supports publicly sharing an OPML file.
  • An OPML reader that displays my newsfeeds in their proper categories.
  • Integration with Wordpress (which my blog runs on), either through a plug-in or a widget
After some Googling, I found the first requirement met in Bloglines, and the others met in the Optimal Browser. The Optimal Browser is very flexible and has a pretty slick interface. It can read an OPML file locally or remotely, and displays expandable categories with expandable RSS feeds!

I installed it, and lo and behold, it didn't work.

The only information I had about the error was "Error reading OPML file," as well as the url of my OPML file and the cache file. How useful. Not.

I tried enabling allow_url_fopen in PHP, as specified in the site's help, by creating a php.ini in my account's root directory. No luck. "Maybe I'm just not doing this right," I thought, "and I could spend hours trying to figure this out. Maybe I'll try installing Curl instead to avoid this particular headache."

Well, installing extra *stuff* in PHP is a headache in itself. There's no easy way to add modules, like in more sane languages such as Perl and Java. To install extra modules not included in the base package, you actually have to RECOMPILE the whole damn PHP package. If I had to actually do that manually in the shell, I'd rather shoot myself.

Luckily, there are easier ways, assuming your server has WHM/Cpanel installed. One way is to use the EasyApache in the shell. The script is usually located at /scripts/easyapache. An even easier way, if you hate the command line as much as I do, is to use EasyApache from within WHM itself. Just log into WHM, find the "Apache Update" link, select your options, and away you go. Easy as pie.

Well, I installed Curl, and it still didn't work. I still had the exact same error. I tried looking at the settings.optimal.inc as specified in the help, but the paths were all correct. I tried uploading the file to my server so it could read it locally, but still no luck. So then I tried modifying the plugin code to output the path AS WELL AS the url of the OPML file. I noticed a small little thing: there was a space between the path and the local url.

Aha! The instructions on the web site said to use this syntax to include the OPML reader on a Wordpress page:
!OPMLRender : url,updatetime,css class,depth,flags
When somebody gives you a syntax definition, you had better use it exactly as given, otherwise you're program won't work. In this case, however, the definition is wrong, and using it as stated will break the code. If you put a space after the colon, it's counted as part of the URL!

Once I fixed this problem, I got another error message! Woo hoo! Change is good! The error was "No valid XSLT processor found." This turned out to be an easy fix. I just ran EasyApache again and recompiled PHP with "Dom XSLT."

Conclusion: Giving incorrect syntax instructions is a cardinal sin. My Outragemeter just maxed out.

Thursday, June 7, 2007

Why can't Blogger escape special characters?

I was typing up yesterday's entry using Blogger's GUI editor. I had to use some special characters (< and >). Normally you would hope that an HTML GUI editor would automatically escape < and > if you copy and paste it. Obviously, if you're in GUI mode and you type < and >, you want to see < and >, not HTML. If you want to put in HTML, you'll switch to HTML. Common sense, right?

Apparently not. Blogger's insane system simply keeps the < and > intact. Even more insanely, it tries to validate your HTML and "fix" it. God forbid you ever try to type <Directory> in your post, because Blogger will insert </directory> and add extra elements. WTF?

I know most web-based HTML GUI editors suffer from this problem. But Blogger is supposed to be cooler than that. C'mon Google, do it right!

The only solution I know of is to use escape characters. I found an HTML Keyboard Bookmarklet, but this solution is a little clunky. Another option is to type your post in a desktop HTML editor (like Dreamweaver), then view the HTML source and copy/paste that into Blogger.

What's even more fun, however, is when you go back to open a previous post, Blogger automatically puts you into wysiwyg mode. And once you go into wysiwyg mode, all your carefully inserted escape characters are converted into non-escaped characters! ARRRGGGHHH! You have to go into Settings and turn off the wysiwyg editor completely to keep this from happening.

There's also a Blogger for Word plug-in. I tried to test it, but it's not accepting my username and password. Oh well, forget it.

Conclusion: This should be Blogger's motto. C'mon, stop sucking and just be cool, okay?

Wednesday, June 6, 2007

Apache + CGI + .htaccess = trouble

I changed the domain name for Bodyzilla (which is running on a Linux box in Apache). I'm running Bugzilla, which God-only-knows-why is written in Perl and runs as CGI. Who in this modern day and age still uses CGI? Everybody has moved onto greener pastures, like PHP, ASP.NET or Java.

Anyway, after changing the domain name Bugzilla stopped working. I had just gone through hell a couple days earlier setting it up. Good thing I have root access to my server... I had to actually modify the httpd.conf to give the bugzilla directory the proper permissions. I hate configuring Apache so I just copy-pasted from some web site. Well, now it wasn't working and I had to find out why.

When your CGI script doesn't work, what happens is you get an Internal 500 error in your browser. This is useless and tells you nothing. If you're lucky, you'll have access to your site's error log. But even if you do, access is useless if you don't know where the error log is LOCATED. The problem with web servers that run on Linux is that every installation seems to be set up differently. You can try Googling to find the path to a certain file, but most of the time the path you find just won't work.

On my server, the web server error log is located at /usr/local/apache/logs/error_log. You can view the last few lines of this gigantic log file with this command:

$~ tail /usr/local/apache/logs/error_log


Doing this, I discovered the error:

/home/bodybugz/public_html/bugs/.htaccess: RewriteEngine not allowed here


Evidently the RewriteEngine needs to be turned on in the bugs directory (which is where Bugzilla is installed). I didn't know why at the time, but in hindsight the .htaccess file contains this line:

RewriteEngine on


It seems that RewriteEngine is off by default, and needs to be specifically turned on for this directory. Luckily, I knew by Googling that I needed to edit my httpd.conf, and the path to this is /etc/httpd/conf/httpd.conf.

Here is what my configuration was:

<Directory /home/bodybugz/public_html/bugs>
AddHandler cgi-script .cgi
Options +Indexes +ExecCGI
DirectoryIndex index.cgi
AllowOverride Limit
</Directory>

And here is what I had to change it to:

<Directory /home/bodybugz/public_html/bugs>
AddHandler cgi-script .cgi
Options +Indexes +ExecCGI
DirectoryIndex index.cgi
AllowOverride All
</Directory>


This allowed the .htaccess to override the default server setting for RewriteEngine.

Don't forget to restart Apache whenever you change the httpd.conf.

$~ service httpd restart


Conclusion: No mere mortal can possibly comprehend all the complexities of Apache configuration. Don't attempt it unless you want your head to explode.

Tuesday, June 5, 2007

Crystal Report Viewer in .NET

We needed to use Crystal Reports to generate some reports for our web project. The project is in ASP.NET 1.1/C#, so we needed .NET integration. We also needed Excel format (XLS) export. We settled on Crystal Reports 11 for its advanced reporting functionality, integrated .NET Crystal Reports viewer, and multiple export options.

To view a Crystal Report on a .NET page, all you have to do is use the included Crystal Report Viewer, which is basically a .NET control. You can save your Crystal Report as a .RPT file, include it in your .NET web project, and a proxy class (of type CrystalDecisions.CrystalReports.Engine.ReportClass) is auto-generated. For example, if your file is located at /MyReport.rpt, a proxy class called MyReport is auto-generated in /MyReport.cs. The Crystal Report Viewer takes this proxy class as its ReportDataSource, and takes as its datasource any bindable data structure (DataTable, DataSet, DataReader, etc.) that matches the schema of the report itself. So if you used a certain database view to generate your report, your Crystal Report Viewer datasource must be selected from this same view.

Here is some sample C# code:

protected CrystalDecisions.Web.CrystalReportViewer CrystalReportViewer1;
protected MyReport report = new MyReport();
...
DataTable dt = SelectFromDatabaseView(arguments);
CrystalReportViewer1.SetDataSource(dt);
CrystalReportViewer1.ReportSource = report;
First Problem: Permissions

The code worked great so we were ready to push it to another server (the test server). But when I tested the code on my own machine, it didn't work. Here's the error I got when I tried to set the DataSource:

"Access to the path \"C:\\DOCUME~1\\DWBUTL~1\\ASPNET\\LOCALS~1\\Temp\\temp_66cf7594-54e8-43ef-959c-8b47b98500ac.rpt\" is denied."

Apparently Crystal Reports was trying to write to some temporary directory it didn't have access to. My IIS instance was set up to impersonate, which means IIS runs as a specific user rather than the default Internet Guest Account (IUSR_). Apparently this also means that the ASP.NET Worker Process (ASPNET) is not being used, but rather the impersonated account. The other developer wasn't set up for impersonation, which is why he didn't encounter the problem.

Of course, if I had set up impersonation properly in the first place, I may not have had this problem. (Detailed instructions for setting up permissions for the impersonation account are located at MSDN.) I got lazy and didn't follow the full instructions, because everything was working fine.

Strangely enough though, Crystal Reports doesn't seem to use the same directories that IIS is supposed to use. On the test server, Crystal Reports used the C:\Windows\Temp folder. On my own machine, it used C:\Documents and Settings\\ASPNET\Local Settings\Temp. If anyone knows why it would use one rather than the other, I'd love to know the answer. That information will come in handy when we push to production.

Second Problem: Missing Virtual Directory

After I fixed the first problem, the report displayed properly. But then we had a second problem: all the images were broken. Viewing the location of the images, I noticed they were located on http:///crystalreportviewers115/. Apparently, the Crystal Report Viewer works by creating a new web application in your Default Web Site. This is linked via a virtual directory to C:\Program Files\Business Objects\Common\3.5\crystalreportviewers115. (This path is different in different Crystal Report versions. See this link for the path to your version.) The problem is, this virtual directory is created ONLY in the Default Web Site. Wow. Geniuses. What happens if you create a new web site in IIS and push your .NET code to there? Everything breaks.

The only way around this, it appears, is to copy the virtual directory crystalreportviewers115 from the Default Web Site to whatever web site you need it in. The geniuses at Business Objects didn't give an option which web site to install into.

This might be easy or hard, depending on your situation. If you have IIS 6, you can export the virtual directory configuration to an xml file, and then create a new virtual directory in another web site from the same xml file. If you have IIS 5, you'll probably need to copy things manually. If your virtual directory is simply gone, you'll have to create it from scratch.

Conclusion: This is so messed up that it makes babies cry and turn to stone.