001    /**
002     * Copyright (c) 2000-2013 Liferay, Inc. All rights reserved.
003     *
004     * This library is free software; you can redistribute it and/or modify it under
005     * the terms of the GNU Lesser General Public License as published by the Free
006     * Software Foundation; either version 2.1 of the License, or (at your option)
007     * any later version.
008     *
009     * This library is distributed in the hope that it will be useful, but WITHOUT
010     * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
011     * FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more
012     * details.
013     */
014    
015    package com.liferay.util.bridges.php;
016    
017    import com.caucho.quercus.servlet.QuercusServlet;
018    import com.caucho.vfs.Path;
019    import com.caucho.vfs.SchemeMap;
020    import com.caucho.vfs.Vfs;
021    
022    import com.liferay.portal.kernel.log.Log;
023    import com.liferay.portal.kernel.log.LogFactoryUtil;
024    import com.liferay.portal.kernel.servlet.BufferCacheServletResponse;
025    import com.liferay.portal.kernel.servlet.DynamicServletConfig;
026    import com.liferay.portal.kernel.servlet.PortletServletObjectsFactory;
027    import com.liferay.portal.kernel.servlet.ServletContextUtil;
028    import com.liferay.portal.kernel.servlet.ServletObjectsFactory;
029    import com.liferay.portal.kernel.util.GetterUtil;
030    import com.liferay.portal.kernel.util.InstanceFactory;
031    import com.liferay.portal.kernel.util.StringBundler;
032    import com.liferay.portal.kernel.util.StringPool;
033    import com.liferay.util.bridges.common.ScriptPostProcess;
034    
035    import java.io.IOException;
036    import java.io.PrintWriter;
037    
038    import java.net.URI;
039    
040    import java.util.Enumeration;
041    import java.util.HashMap;
042    import java.util.Map;
043    
044    import javax.portlet.ActionRequest;
045    import javax.portlet.ActionResponse;
046    import javax.portlet.GenericPortlet;
047    import javax.portlet.PortletConfig;
048    import javax.portlet.PortletException;
049    import javax.portlet.PortletURL;
050    import javax.portlet.RenderRequest;
051    import javax.portlet.RenderResponse;
052    
053    import javax.servlet.ServletConfig;
054    import javax.servlet.http.HttpServletRequest;
055    import javax.servlet.http.HttpServletResponse;
056    
057    /**
058     * @author Jorge Ferrer
059     */
060    public class PHPPortlet extends GenericPortlet {
061    
062            @Override
063            public void destroy() {
064                    if (quercusServlet != null) {
065                            quercusServlet.destroy();
066                    }
067            }
068    
069            @Override
070            public void doDispatch(
071                            RenderRequest renderRequest, RenderResponse renderResponse)
072                    throws IOException, PortletException {
073    
074                    String phpUri = renderRequest.getParameter(_PHP_URI_PARAM);
075    
076                    if (phpUri != null) {
077                            processPHP(phpUri, renderRequest, renderResponse);
078                    }
079                    else {
080                            super.doDispatch(renderRequest, renderResponse);
081                    }
082            }
083    
084            @Override
085            public void doEdit(
086                            RenderRequest renderRequest, RenderResponse renderResponse)
087                    throws IOException, PortletException {
088    
089                    if (renderRequest.getPreferences() == null) {
090                            super.doEdit(renderRequest, renderResponse);
091                    }
092                    else {
093                            processPHP(editUri, renderRequest, renderResponse);
094                    }
095            }
096    
097            @Override
098            public void doHelp(
099                    RenderRequest renderRequest, RenderResponse renderResponse) {
100    
101                    processPHP(helpUri, renderRequest, renderResponse);
102            }
103    
104            @Override
105            public void doView(
106                    RenderRequest renderRequest, RenderResponse renderResponse) {
107    
108                    processPHP(viewUri, renderRequest, renderResponse);
109            }
110    
111            @Override
112            public void init(PortletConfig portletConfig) throws PortletException {
113                    super.init(portletConfig);
114    
115                    editUri = getInitParameter("edit-uri");
116                    helpUri = getInitParameter("help-uri");
117                    viewUri = getInitParameter("view-uri");
118    
119                    addPortletParams = GetterUtil.getBoolean(
120                            portletConfig.getInitParameter("add-portlet-params"), true);
121    
122                    String servletObjectsFactoryName = GetterUtil.getString(
123                            getInitParameter("servlet-objects-factory"),
124                            PortletServletObjectsFactory.class.getName());
125    
126                    try {
127                            Class<?> servletObjectsFactoryClass = Class.forName(
128                                    servletObjectsFactoryName);
129    
130                            servletObjectsFactory =
131                                    (ServletObjectsFactory)servletObjectsFactoryClass.newInstance();
132                    }
133                    catch (Exception e) {
134                            throw new PortletException(
135                                    "Unable to instantiate factory" + servletObjectsFactoryName, e);
136                    }
137            }
138    
139            @Override
140            public void processAction(
141                    ActionRequest actionRequest, ActionResponse actionResponse) {
142    
143                    String phpURI = actionRequest.getParameter(_PHP_URI_PARAM);
144    
145                    if (phpURI != null) {
146                            actionResponse.setRenderParameter(_PHP_URI_PARAM, phpURI);
147                    }
148            }
149    
150            protected synchronized void initQuercus(ServletConfig servletConfig)
151                    throws PortletException {
152    
153                    if (quercusServlet != null) {
154                            return;
155                    }
156    
157                    try {
158                            SchemeMap schemeMap = Vfs.getDefaultScheme();
159    
160                            URI rootURI = ServletContextUtil.getRootURI(
161                                    servletConfig.getServletContext());
162    
163                            schemeMap.put(
164                                    rootURI.getScheme(),
165                                    new ServletContextPath(servletConfig.getServletContext()));
166    
167                            Path.setDefaultSchemeMap(schemeMap);
168    
169                            quercusServlet = (QuercusServlet)InstanceFactory.newInstance(
170                                    _QUERCUS_SERVLET);
171    
172                            Map<String, String> params = new HashMap<String, String>();
173    
174                            Enumeration<String> enu = servletConfig.getInitParameterNames();
175    
176                            while (enu.hasMoreElements()) {
177                                    String name = enu.nextElement();
178    
179                                    if (!name.equals("portlet-class")) {
180                                            params.put(name, servletConfig.getInitParameter(name));
181                                    }
182                            }
183    
184                            servletConfig = new DynamicServletConfig(servletConfig, params);
185    
186                            QuercusServlet.PhpIni phpIni = quercusServlet.createPhpIni();
187    
188                            phpIni.setProperty("unicode.http_input_encoding", StringPool.UTF8);
189                            phpIni.setProperty("unicode.output_encoding", StringPool.UTF8);
190                            phpIni.setProperty("unicode.runtime_encoding", StringPool.UTF8);
191                            phpIni.setProperty("unicode.semantics", Boolean.TRUE.toString());
192    
193                            quercusServlet.init(servletConfig);
194                    }
195                    catch (Exception e) {
196                            throw new PortletException(e);
197                    }
198            }
199    
200            protected void processPHP(
201                    String phpURI, RenderRequest renderRequest,
202                    RenderResponse renderResponse) {
203    
204                    try {
205                            ServletConfig servletConfig =
206                                    servletObjectsFactory.getServletConfig(
207                                            getPortletConfig(), renderRequest);
208    
209                            initQuercus(servletConfig);
210    
211                            HttpServletRequest request =
212                                    servletObjectsFactory.getServletRequest(renderRequest);
213                            HttpServletResponse response =
214                                    servletObjectsFactory.getServletResponse(
215                                            renderRequest, renderResponse);
216    
217                            PHPServletRequest phpRequest = new PHPServletRequest(
218                                    request, servletConfig, renderRequest, renderResponse,
219                                    getPortletConfig(), phpURI, addPortletParams);
220    
221                            BufferCacheServletResponse bufferCacheServletResponse =
222                                    new BufferCacheServletResponse(response);
223    
224                            quercusServlet.service(phpRequest, bufferCacheServletResponse);
225    
226                            String result = bufferCacheServletResponse.getString();
227    
228                            String contentType = bufferCacheServletResponse.getContentType();
229    
230                            if (contentType.startsWith("text/")) {
231                                    result = rewriteURLs(result, renderResponse.createRenderURL());
232                            }
233    
234                            renderResponse.setContentType(contentType);
235    
236                            PrintWriter writer = renderResponse.getWriter();
237    
238                            writer.write(result.toCharArray());
239                    }
240                    catch (Exception e) {
241                            _log.error("Error processing PHP", e);
242                    }
243            }
244    
245            protected String rewriteURLs(String page, PortletURL portletURL) {
246                    ScriptPostProcess scriptPostProcess = new ScriptPostProcess();
247    
248                    scriptPostProcess.setInitalPage(new StringBundler(page));
249    
250                    scriptPostProcess.postProcessPage(portletURL, _PHP_URI_PARAM);
251    
252                    return scriptPostProcess.getFinalizedPage();
253            }
254    
255            protected boolean addPortletParams;
256            protected String editUri;
257            protected String helpUri;
258            protected QuercusServlet quercusServlet;
259            protected ServletObjectsFactory servletObjectsFactory;
260            protected String viewUri;
261    
262            private static final String _PHP_URI_PARAM = "phpURI";
263    
264            private static final String _QUERCUS_SERVLET =
265                    "com.caucho.quercus.servlet.QuercusServlet";
266    
267            private static Log _log = LogFactoryUtil.getLog(PHPPortlet.class);
268    
269    }