IIS中加入piwik跟踪代码

好久没来写博了...

今天写一下如何在IIS中加入piwik跟踪代码。

背景:

• piwik 开源php站点统计程序 http://piwik.org

• HttpModule: http://www.cnblogs.com/stwyhm/archive/2006/08/09/471729.html

实现思路:通过HttpModule在aspx页面的body前加入统计代码。

代码实现:

1. 新建dll项目

using System;
using System.Data;
using System.Configuration;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using System.IO; 

namespace PiwikAnalytics
{
    /// 修改于网上流传的Google Analytics (https://www.google.com/analytics/) script    
    public class PiwikAnalyticsModule : IHttpModule
    {
        static string GoogleScript = string.Empty;
        HttpApplication application; 

        public void Dispose()
        {
            //context.BeginRequest -= new EventHandler(OnBeginRequest);
        } 

        public void Init(HttpApplication context)
        {
            context.BeginRequest += new EventHandler(OnBeginRequest);
            application = context;
        } 

        void OnBeginRequest(object sender, EventArgs e)
        {
            HttpApplication application = (HttpApplication)sender;
            //web.config中定义的站点字符串,后面会有介绍
            string sites = ConfigurationManager.AppSettings["PiwikAnalyticsSites"];
            //此处未进行异常处理,大家发布时记得加上哦~
            string[] siteArr = sites.Split(';');
            string siteid = "5";
            foreach (string site in siteArr)
            {
                if (application.Request.Url.OriginalString.ToLower().IndexOf(site.Split(',')[0]) > 0)
                {
                    siteid = site.Split(',')[1];
                }
            } 

            GoogleScript = @" <!-- Piwik -->
             <script type=""text/javascript"">
        var pkBaseURL = ((""https:"" == document.location.protocol) ? ""https://yourpiwik.com/piwik/"" : ""http://yourpiwik.com/piwik/"");
        document.write(unescape(""%3Cscript src='"" + pkBaseURL + ""piwik.js' type='text/javascript'%3E%3C/script%3E""));
    </script> 

    <script type=""text/javascript"">
        //try {          
            var piwikTracker = Piwik.getTracker(pkBaseURL + ""piwik.php"", " + siteid + @");           
            piwikTracker.trackPageView();
            piwikTracker.enableLinkTracking();
        //} catch (err) { }
    </script> 

    <noscript>
        <p>
            <img  /></p>
    </noscript>
            <!-- End Piwik Tag -->"; 

            //这里需要针对ASPX页面进行拦截
            string[] temp = application.Request.CurrentExecutionFilePath.Split('.');
            if (temp.Length > 0 && temp[temp.Length - 1].ToLower() == "aspx")
            {
                application.Response.Filter = new AnalyticsStream(application.Response.Filter);
            }
        } 

        class AnalyticsStream : Stream
        {
            Stream innerStream;          
            MemoryStream memory = new MemoryStream(); 

            public AnalyticsStream(Stream innerStream)
            {
                this.innerStream = innerStream;            
            } 

            public override void Close()
            {
                memory.Position = 0;
                using (StreamWriter writer = new StreamWriter(innerStream))
                {
                    using (StreamReader reader = new StreamReader(memory))
                    {
                        while (!reader.EndOfStream)
                        {
                            // Find </body>
                            if (MatchesOrWrite(reader, writer, '<', null) &&
                                MatchesOrWrite(reader, writer, '/', "<") &&
                                MatchesOrWrite(reader, writer, 'b', "</") &&
                                MatchesOrWrite(reader, writer, 'o', "</b") &&
                                MatchesOrWrite(reader, writer, 'd', "</bo") &&
                                MatchesOrWrite(reader, writer, 'y', "</bod") &&
                                MatchesOrWrite(reader, writer, '>', "</body"))
                            {
                                //string script = String.Format(GoogleScript, accountNumber) + "</body>";
                                writer.Write(GoogleScript);
                                while (!reader.EndOfStream)
                                    writer.Write((char)reader.Read());
                            }
                        }
                    }
                } 

                base.Close();
            } 

            private bool MatchesOrWrite(StreamReader reader, StreamWriter writer, char target, string buffered)
            {
                if (!reader.EndOfStream)
                {
                    char current = (char)reader.Read();
                    if (current == target)
                    {
                        return true;
                    }
                    else
                    {
                        writer.Write(buffered);
                        writer.Write(current);
                    }
                }
                else
                {
                    writer.Write(buffered);
                } 

                return false;
            } 

            public override bool CanRead
            {
                get { return memory.CanRead; }
            } 

            public override bool CanSeek
            {
                get { return memory.CanSeek; }
            } 

            public override bool CanWrite
            {
                get { return memory.CanWrite; }
            } 

            public override void Flush()
            {
                memory.Flush();
            } 

            public override long Length
            {
                get { return memory.Length; }
            } 

            public override long Position
            {
                get
                {
                    return memory.Position;
                }
                set
                {
                    memory.Position = value;
                }
            } 

            public override int Read(byte[] buffer, int offset, int count)
            {
                return memory.Read(buffer, offset, count);
            } 

            public override long Seek(long offset, SeekOrigin origin)
            {
                throw new NotImplementedException();
            } 

            public override void SetLength(long value)
            {
                memory.SetLength(value);
            } 

            public override void Write(byte[] buffer, int offset, int count)
            {
                memory.Write(buffer, offset, count);
            }
        }
    }
} 

2.

编译得到PiwikAnalytics.dll,注册到GAC中【需要强命名的哦~】,不然要每个子站点都拷贝一份。

如何在visual studio中强命名程序集:(推荐) http://www.cnblogs.com/awpatp/archive/2010/02/07/1665530.html

文章中也提到了如果获取程序集的PublicKeyToken,其实不用那么麻烦,把程序集放到GAC中,有一列会显示PublicKeyToken的~。

• GAC注册:http://www.cnblogs.com/mljmalongjiang/archive/2008/07/31/1257135.html

• 另外有种更简便的方式,直接把dll托到 c:\windows\assembly文件夹中【推荐】

另外一种方式强命名程序集:http://www.cnblogs.com/zhongge/articles/1207183.html

经过上述步骤,我们已经把PiwikAnalytics.dll注册到GAC了,那我们在web.config中做一下配置就要大功告成了!

3. web.config默认路径C:\inetpub\wwwroot,如果没有web.config可直接新建的~

<?xml version="1.0"?>
<configuration>
  <appSettings>
    <add key="PiwikAnalyticsSites" value="site,4;meeting,6"/>    
  </appSettings>
  <system.web>    
    <authentication mode="Windows"/>
    <httpModules>
      <add name="PiwikAnalytics" type="PiwikAnalytics.PiwikAnalyticsModule"/>
    </httpModules>
    <compilation debug="true">
      <assemblies>
        <add assembly="PiwikAnalytics, version=1.0.0.0, Culture=neutral,PublicKeyToken=0c64deee0d840dfb" />
      </assemblies>
    </compilation>
  </system.web>
</configuration> 

要记得把从步骤2中得到的PublicKeyToken替换成你自己的哦~

到此时,重启iis,刷新页面。再去piwik中查看,大功告成!

需特别注意的地方:

1. 注册module时,要按照自己的实际情况配置

2. 上述方式不适用于MVC和模板模式开发

3. 每次改写代码的时候都需要重新生成一次DLL,并且重新注册GAC,并且对站点相应应用程序池中的进行回收

More:另外介绍2个pwiki客户端查看软件

Desktop Web Analytics

Piwik Connector

Over 收工!