
Copyright © 2003, 2004 - Locati Stefano. All rights reserved.
Abstract
Since Obliquid software and concepts are getting more stable, we are now starting the documentation effort. This manual has been started on May 18th, 2003. Many sections have to be reviewed.
Obliquid is a PHP/XML framework for building groupware Web portals. It provides Lego bricks that may be composed to build an Internet application. It has multilingual support and themes. Modules include user management, calendar, news, CMS, and messaging. For more information dev.obliquid.com
Last modified June 09, 2004
Table of Contents
List of Tables
List of Examples
We will give you a short overview of Obliquid and detailed installation instructions for Unix and Windows. Read only the first chapter "Introduction to Obliquid" to understand if Obliquid is for you before trying it.
Table of Contents
Table of Contents
Obliquid is more than a groupware application, it's an application framework to build web based PHP applications. For this reason Obliquid may be used, administered, customized and programmed by people with different backgrounds, like employees, managers, web agencies, graphic designers and programmers. The logical organization of this book takes this into consideration and the book may be read from cover to cover, or skipping chapters, as needed.
Even the simple question "What is Obliquid" may have different answers according to the audience. So, for end users it is a groupware application with user management, a calendar application, a news publishing system, and a documentation management system with the ability to send alert emails on certain events. For administrators it is a web application with a fine grained permission system, able to manage thousands contacts, helping to manage the workflow with alert emails. Graphic designers may be pleased to hear that the appearence may be fully customized by creating a new theme, and that since every part of html layout is in template files, pixel alignments are possibile. Programmers may like the concept of building the page with prebuilt blocks, and adding their own blocks, the possibility to separate common parts from customizations, and the powerful permission system.
Why should somebody bother to evaluate Obliquid when there are many similar open source groupware applications? If you install a groupware application and it already works exactly the way you need, then you are a lucky guy. But if you have to make modifications, even small ones, then you will understand the big difference between Obliquid and similar projects. Keep on reading to know more.
As an example we examine the month view of the calendar module: supported events are availabilities (a person gives his/her availabilities for meetings), phone calls (to keep a record of phone calls we made and to whom), recalls (to remember to phone again, since the first call was not enough), meetings (with the possibility to send confirmation emails), accounting entries and work sessions.

By clicking the rightmost icon of the top bar, anybody with an appropriate permission can see the skeleton of a page. For example this is the structure of the previous calendar page.
A page is not a monolith script, but it's composed of slots. In this example there are five slots used. CORE/NAV is the navigation bar across the top, CAL/MONTHSMALL is the mini-calendar on the left, CAL/INDEX is the mini-navigation under the small calendar, and USER/LOGIN is logout option under that, and CAL/MONTH is the month view on the right. Slots are placed on a 3x6 grid and they can be moved around, they can be deleted, they can be edited, they can be replaced with your modified ones and new slots can be added. Slots have a PHP source and a Smarty template, to keep source code separated from HTML.

In a famous open source groupware application, the calendar homepage did use Smarty templates, but was a monolith of over 1300 lines. In our example cal/monthsmall is 103 lines and cal/month is 210 lines. This is not just numbers, it can save you headaches.
User search features search by surname, name, organization, city and username. It's possible to see only members of a group, or to find people not members of any group. It's then possible to filter by an Italian District: soon this filter could be replaced by search by Country, if the site administrator prefers. Search results are divided in pages, if a search exceedes 50 results.


In the user search configuration it's possible to decide which fields will be shown in the search result table. The order in which the fields are shown can be modified too.
In the user edit page an administrator can change user data, enable or disable a user to login, change his/her password, and change group memberships to allow access or restrict to parts of the site.

In the user edit configuration, the site configurator can choose which of the fields defined in the user database table are enabled or disabled and in which order they are to be shown.

Objects can be categorized according to three different categories. Moreover they can be classified by document type and by language. The titles for the three categories are "Category 1", "Category 2" and "Category 3". These can be changed during the system installation, or they can be changed with the site configuration parameters.

The person in charge with document approvals can be notified of new documents with an email, or can see the list of documents to be approved from the site. He/she can approve or not a document: in any case an email, with an optional comment will be sent to the person who inserted the document. This email can be blocked with the message center configuration, if desired.

We have an online demo of the latest released version. There are three different demo logins with different access rights. In Obliquid, access rights are assigned to groups, and persons may belong to zero or more groups.
In the demo example Blaise Pascal is member of the Developer group which has full access, Albert Einstein is member of the Administrator group which can administer the site, but not to change it, Jan van de Snepscheut is member of the Customer group and has the lowest access rights. This is just an example. More groups can be created as needed and permissions can be fine tuned.
The demo site may be accessed at demo.obliquid.com. Since developer access has full rights to the site, including deleting pages, the demo site may be broken from time to time. For this reason a responsible use of the demo site is encouraged. On the other hand if you notice that the demo site is not working, please let us know this through the support section of dev.obliquid.com.
Some case studies on who uses Obliquid and how.
Kines uses Obliquid to manage more than ten thousand business contacts. Five employees manage work meetings for nearly a hundred photographers, scattered across Italy.
I cannot write the name here, because I have to ask them the authorization to do so first. The intranet/extranet of this firm is built around Obliquid with many custom additions. Many different groups have different views of the system: administrators, about 200 dealers, support people, technical agents.
Obliquid was first released as free software in July 2002. Obliquid is also the name of a software firm and an Internet provider. The name of the project was chosen to be the same as our company name because it's our main project and most of our customers' site are built around it. Our typical customers are medium to big sized firms that require organizational consultancies and custom solutions, more than a boxed product. We decided to release it as free software for a very simple reason: there was no reasons against it, no reasons to keep it secret.
The first result of releasing it as free software was to force us to make Obliquid cleaner and more organized. A programmer writes messy code from time to time, to meet impossible deadlines or for just being lazy. But he/she will be very ashamed of it, if other programmers look at it. Going open source the whole world can read your code. Scary. We rewrote it from scratch while improving the features of our previous engine.
In a second phase we started to receive bug reports from a wider user base. Bug reports help us to improve Obliquid, because we can fix any bug reported, but we can't fix bugs that we don't know about.
The next phase has just started: we are receiving translations and help from programmers to improve Obliquid. Obliquid was built with multilanguage support from the very beginning, because we are located in Italy and releasing it in Italian only would have been an unwise move. Moreover we've already built sites in Chinese and Japanese for our customers, and we are aware of the problems posed by different character encodings. Obliquid uses UTF-8 encoding which is safe for nearly all the languages of the world. Programmers are also starting to help and join the team to be part of this adventure.
The Obliquid developers' group now goes beyond Obliquid and so any of the active developers is the most qualified person available to give professional support and to customize Obliquid for specific needs. Beyond the free support anyone can receive on the forum, Obliquid firm can offer professional pay support, customizations, hosting or housing for your site.
Table of Contents
Obliquid needs a platform with the following components
If needed database and webserver may be on different hosts.
If you are an expert, or you want an overview of the setup process, read this section, otherwise follow the step by step installation instructions in the next section.
Make sure your target system meets the requirements. Explaining how to install Apache 1.3.x, PHP 4.1.x or higher, MySQL 3.23.x or higher is beyond the scope of this document.
You can download the latest release of Obliquid from dev.obliquid.com or directly from sourceforge. It's recommended that you download the tar.gz package of the latest release.
If you've downloaded Obliquid directly on the system where it has to be installed you can move it to a location visible through the webserver.
For example:
mv obliquid-rel#.tar.gz /var/www tar xfvz obliquid-rel#.tar.gz
It will create a directory named obliquid-rel#, where rel# will be the release number, such as 0.5.0, for example. You are now free to rename this directory with the name you prefer.
If you have only ftp access, you can unpack the archive on your system and then upload it to the final destination.
Point your browser to the just unpacked or uploaded Obliquid directory, for example to http://localhost/obliquid-rel# - you should see the welcome screen. Click on the I agree button if you agree to GNU LGPL licencing terms. Obliquid is free software, a software that gives you many freedoms, but remember that it's not public domain software. For example you can't remove the copyright notice, take away the credits, give to others without giving them the same rights given to you.
In this step your environment will be checked. It will be checked that at least PHP 4.1.0 is installed and that the memory limit is big enough. Further, file permissions and magic_quotes settings are checked too.
Turning off PHP magic_quotes.
If you have root access to the webserver, locate your php.ini and make sure that magic_quotes_gpc, magic_quotes_runtime, magic_quotes_sybase are all set to Off.
; Magic quotes for incoming GET/POST/Cookie data. magic_quotes_gpc = Off ; Magic quotes for runtime-generated data, e.g. data from SQL, from exec(), etc. magic_quotes_runtime = Off ; Use Sybase-style magic quotes (escape ' with '' instead of \'). magic_quotes_sybase = Off
If you don't have root access you can disable magic quotes using a .htaccess file. Write a text file with the content below, and drop it in the main Obliquid directory, naming it .htaccess.
php_value magic_quotes_gpc Off php_value magic_quotes_runtime Off php_value magic_quotes_sybase Off
Starting the setup script
If you have command line access, running sh common/scripts/startsetup in Obliquid directory will fix file permissions. Otherwise you've to make the listed files writeable to the webserver.
If an important requirement is not met, the go to step 2 button won't appear. You can try to fix the problems, and pushing the Retry button until the problems are solved.
Create new database checkbox: lets you decide to create tables in a new database or to use an existing one. Note that, by using two different table prefixes, two Obliquid installations may live in the same database.
Don't modify Database Type, since only MySQL is supported at the moment, and skip directly to Database Host. This setting lets you connect to a database on a different machine. Most of the time you won't need this feature, so you can leave "localhost" there.
Provide a reasonable "Database Name". Don't use spaces, use only alphabetic letters and numbers. If the Create a new database? option is not checked, you have to provide the name of an existing database.
As you reach step 3 you will either see a Connection OK message or some error message. For example if you mistyped the password you will have Could not connect to MySQL server message, in this case a Retry Step 2 button will appear.
If the connection was successfully established, then a Create DB and go to step 4 button will appear. This process takes some time, and should not be interrupted.
Multilanguage messages will get imported in this step. All you have to do is click on Import messages and go to step 6 button and wait. This step may take a long time, so be sure to click only once and to leave it running.
Now Obliquid is installed. The only thing left behind is to replace the setup script with the main index. This can be done by running sh common/scripts/endsetup or by simply replacing index.php with common/scripts/index.php.
After this step you can reload the page and start to use Obliquid.
Table of Contents
Obliquid needs a platform with the following components
If needed database and webserver may be on different hosts.
If you are expert, or you want an overview of the setup process, read this section, otherwise follow the step by step installation instructions in the next section.
Make sure your target system meets the requirements. Explaining how to install Apache 1.3.x, PHP 4.1.x or higher, MySQL 3.23.x or higher is beyond the scope of this document. Easyphp provides an easy installation of a bundle of PHP, MySQL and Apache for your convenience.
Make sure that PHP has magic_quotes off.
If you have root access to the webserver, locate your php.ini and make sure that magic_quotes_gpc, magic_quotes_runtime, magic_quotes_sybase are all set to Off.
; Magic quotes for incoming GET/POST/Cookie data. magic_quotes_gpc = Off ; Magic quotes for runtime-generated data, e.g. data from SQL, from exec(), etc. magic_quotes_runtime = Off ; Use Sybase-style magic quotes (escape ' with '' instead of \'). magic_quotes_sybase = Off
If you don't have root access you can disable magic quotes using a .htaccess file. Write a text file with the content below, and drop it in the main Obliquid directory, naming it .htaccess.
php_value magic_quotes_gpc Off php_value magic_quotes_runtime Off php_value magic_quotes_sybase Off
You can download the latest release of Obliquid from dev.obliquid.com or directly from sourceforge. It's recommended that you download the zip package of the latest release.
If you've downloaded Obliquid directly on the system where it has to be installed you can move it to a location visible through the webserver.
For example:
mv obliquid-rel#.tar.gz /var/www tar xfvz obliquid-rel#.tar.gz
It will create a directory named obliquid-rel#, where rel# will be the release number, such as 0.5.0, for example. You are now free to rename this directory with the name you prefer.
If you have only ftp access, you can unpack the archive on your system and then upload it to the final destination.
Point your browser to the just unpacked or uploaded Obliquid directory, for example to http://localhost/obliquid-rel# - you should see the welcome screen. Click on the I agree button if you agree to GNU LGPL licencing terms. Obliquid is free software, a software that gives you many freedoms, but remember that it's not public domain software. For example you can't remove the copyright notice, take away the credits, give to others without giving them the same rights given to you.
In this step your environment will be checked. It will be checked that at least PHP 4.1.0 is installed and that the memory limit is big enough. Further, file permissions and magic_quotes settings are checked too.
If you have access to the system, running common/scripts/startsetup.bat in Obliquid directory should fix file permissions. Otherwise you've to make the listed files writeable to the webserver.
If an important requirement is not met, the go to step 2 button won't appear. You can try to fix the problems, and pushing the Retry button until the problems are solved.
Create new database checkbox, lets you decide if to create a new database or to use an existing one. Note that, by using two different table prefix two Obliquid installations may live in the same database.
Don't modify Database Type, since only MySQL is supported at the moment, and skip directly to Database Host. This setting let you connect to a database on a different machine. Most of the time you won't need this feature, so you can leave "localhost" there.
Provide a reasonable "Database Name". Don't use spaces, use only alphabetic letters and numbers. If Create a new database? option is not checked, you have to provide the name of an existing database.
As you reach step 3 you will either see a Connection OK message or some error message. For example if you mistyped the password you will have Could not connect to MySQL server message: in this case a Retry Step 2 button will appear.
If the connection could be successfully established, then a Create DB and go to step 4 button will appear. This process takes some time, and should not be interrupted.
Multilanguage messages will get imported in this step. All you have to do is click on Import messages and go to step 6 button and wait. This step may take a long time, so be sure to click only once and to leave it running.
Now Obliquid is installed. The only thing left behind is to move away this setup script and to replace it with the main index. This can be done by running common/scripts/endsetup.bat or by simply replacing index.php with common/scripts/index.php.
After this step you can reload the page and start to use Obliquid.
How to use the web interface of Obliquid, as end users or administrators.
The USER module provides functions to control who has access to your site, and what they can do. For security reasons, you should closely control who has access to the various user functions.
User administration is relatively simple and straight forward. You can add a user, delete a user, or change their personal information.
There is a set of filters available which will allow you to select which users to display, and in what order to display them. This can simplify your tasks if there are a large number of users. You can limit the display to only those users in a particular group. There is also an Address Book alphabet which will limit the display to only those users where the first letter of the "Sorted By" field matches. Note that you must hit the "OK" button after you make the list box selection in order for the filter to be activated. Obliquid will display 50 user records at a time, with paging arrows if more records are available.
When creating a new user, there are two fields which you should pay special attention to. The first is the checkbox field: "Enable to login". If this box is not checked, then the user will not be able to login, even though they exist. The second special field is the Group select box. This defaults to "none". If you do not assign a user to a group, then they will have very limited access to the rest of Obliquid.
Groups are the way to organize users into collections. This will simplify some of the administration of users. Rather than try to keep track of which user can access what, you only need to assign users to a group, and then decide what that group can access.
Obliquid does not limit the number of groups in the system. A large number of groups could result in increased administration if they are not carefully selected. A user can belong to any number of groups. The default installation defines three groups.
Security is an important part of Obliquid. Various features and functions of Obliquid are represented by Security Objects. Permission to access these objects is assigned to a group. If a user is a member of a group that has access to the object, then that user has access to the object. Since a user can be a member of any number of groups, and any group can be given access to any security object, security configuration is a complex task and should be done carefully.
There are four different types of security objects defined in Obliquid.
Table of Contents
The NEWS module provides a simple, easy to use way to provide news and information to your users. The news can be grouped into categories, and each category can have a set of files for different languages. There are a lot of overlapping features in NEWS and POSTS, but NEWS makes it a little easier to publish the same information in multiple languages.
Administration of the news functions is a relatively simple process. There are only three steps involved in publishing something in news.
First, you need to decide which category you want to put the news article in. If it does not fit into a current category, or you are just starting out, you will need to create a new category.
Second, add an item entry to the category. This will provide a title and sub-title to the item, so your users can know which item they want to view.
Third, you need to add the content, and attach any files that should go with the item. The content can be either simple text information, or it can contain HTML (if you have IE 5.5 or higher).
The news category is a way of grouping news items to make it easier for your users to find the information that they need. When you create a category, you will be given an opportunity to provide a title and description in a number of different languages. The user will see the category titles in their selected language, and be shown how many categories are available in the other Obliquid languages.
There are a number of pieces of information about a category that the administrator should be aware of. They will help you organize the category to suit your needs.
Most of the administration of an item is simple. Care needs to be taken when adding an item to ensure that the language is properly set. If this is not done, then your users may be confused, or not be presented with all the information.
The language that an item is stored in depends on which language version of the category it is added to. When you administer NEWS, be sure that your language selection is correct. NEWS will display a category in the user language if a version is available for that language. Otherwise, it will display the English version. The language setting for an item is based on the version of the category it is added to. For example.... You have created a category that has both an English and an Italian version.
If you set your language preference to English, then the English version of the category will be displayed, and if you add an item to that category entry, it will be added with an English language setting.
If you do not set your language preference to Italian and add an item to the Italian version of the category, then there will be no items to display for your Italian visitors, even though the category will be listed.
When your users display the category and items, those who have English as their language preference will see the category, and an item. Those who have Italian as their langugage preference will only see the category, but no items.
If you want to include files with an item, this is possible. When you add or modify and item, there is a button Add a file. If you press this, the system will pop up a standard browser upload window where you can select a file to be uploaded to the server. When your user clicks on the filename while viewing and item, the file will be downloaded to their computer using the standard browser download functions.
Please note: After you select a file to upload and the popup window closes, the file is not available for your users until you hit the OK button for the item page. This tells Obliquid that you want to accept all the changes and additions for the item. If you do not do this, then the file might be orphaned on your server. It will not harm anything, but it will take up space.
Table of Contents
The POSTS feature of Obliquid allows you to easily post content on your web site. You can put items for display or to be used as part of a newsletter.
There are three steps to making a posting available to your users.
The first step is to determine which category you want to put the new posting in. If the item does not fit into one of the existing categories, or you are just starting out, you will need to create a new category.
Once you have picked the category, then you will need to decide whether the new object will be part of an existing item, or will be a new item. An item represents a group of objects which will be displayed on the same Obliquid page, or be part of the same Obliquid newsletter.
Finally, you will need to add the object itself to the item. An object can be a preformatted text file, an file which contains HTML to provide additional formatting functions, a file which can be downloaded by the users, or an image file (currently only JPG, GIF and PNG files are supported).
A POSTS category is a way of grouping items that are related. The POSTS administrator should decide what to call each category. There are a number of pieces of information which are kept about a category.
A POSTS item is a way of collecting a number of objects which are to be displayed on the same page, or included in the same newsletter. You would normally expect to have more than one item in a category. But an item can ONLY be in ONE category. There are a number of pieces of information which are kept about an item.
A POSTS object is actually a file that has been uploaded to Obliquid and is part of a page that gets displayed to the user or is part of the newsletter. You would normally expect to have more than one object in an item. But an object can ONLY be in ONE item. There are a number of pieces of information which are kept about an object.
Table of Contents
The documentation management was done to be able to manage a good deal of categorized documentation, like in a medium sized organization. In one installation is used to manage more than three thousands documents stored in various formats. This project is now in the test phase.
Each item of documentation may contain zero or more attached objects and they can be searched through different criteria. Each item can be of a Document type, and can have a title, a codification number, and a year. Further an item can be assigned to three different types of categories. Category type 1 and 2 can be assigned only once, while category type 3 can be assigned multiple times.
After a successful setup, Obliquid sets these three categories names to “Category 1”, “Category 2” and “Category 3”. This is of course not meaningful, because you have to change these labels depending on your application. For example if you load the demo data these categories will be renamed “Type”, “Body part” and “Animal”.
Another example is “Brand”, “Part”, “Product”. In this example, a document may describe a part of a product or of many similar products.
To change the labels for your own needs, click on Configure site, or any icon or link you have to access the core module. Then click on Configure parameters link. There locate cat1_name, cat2_name, cat3_name parameters and assign your own values.
The next step would be to insert a few values in the categories, so you can then add an item. To do so, visit “Manage Category 1” and add at least a category label. Note that if you've renamed “Category 1” as you should, also this link will be renamed. It could be “Manage Brand”, for example.
Add at least a value also to all other categories, so visit “Manage Category 2”, “Manage Category 3” and also “Manage Document type”. Document types are not meant for storing the file type (such as PDF files, Word files, or the like), but to store the type of document of an organization, like invoices, internal documentations, proposals and so on. After this you are not yet done because you've to add at least a language: click on “Manage Language” and insert a two letter language code and a language name. Don't make your own language abbreviations, please refer to ISO639 standard. In some cases you may want to use the longer abbreviation, like for traditional chinese: zh_TW, since zh only is still ambiguous between traditional and simplified chinese.
If you followed all the recommendations of the two previous sections, you are now ready to insert your first item; if you didn't go back and execute all the steps before going further.
In the Add a new document page you have to fill in at least the title, but an item without a file is useless, because it can't contain any useful information, so, normally you would add at least a file too.
If an item is inserted without attaching any object it won't trigger any event, but if one object is attached it will trigger an event called doc_newobj. If this event is active in the message center, it will send an email to any people subscribed to this event, refer to the message center documentation for further details. Normally people subscribed to this kind of event will be the ones responsible for approving it.
If you have the permission to do so, you may have received a warning email that a document has been inserted, or if not, you can click on Documents to be approved. You will see a simple list of documents not approved yet, you can choose one, review, and decide wether to approve objects in it or not.
Approval is on objects not on documents, because objects represent the real content. Further is a new object is added to an existing item, there is no reason to hide the whole object from public view until the new object is approved. By clicking on Approve object you get into a screen where you can insert a comment and press on Approve object button. This comment will be sent to the person who inserted the object, provided that the doc_appr event is enabled. This message will be sent also to any other people subscribed to this event.
If you press on the Don't approve object button instead, nothing will happen, but the doc_notappr event will be triggered. If this event is active, the person who inserted the object will receive this comment, together with any people subscribed to this event.
The search slot is shown when clicking on Documentation management, and can be reached from within the doc module by clicking on Search documents. Documents may be searched by title, categories, document type, document number range and reference year.
After clicking on a document, if you have the permission to modify it, a Modify document link will appear. By clicking on it the document may be modified: new objects can be added or deleted or the basic document data may be changed. If a new object is added, a doc_newobj event is triggered, and messages will be sent to persons subscribed to this event. Also doc_moditem event will be triggered and messages will be sent to any person subscribed to this event.
Table of Contents
The message center feature acts as a central clearing house for the sending of predetermined messages. Some modules such as POSTS allow you to post items which need to be approved before they are available. Rather than have the POSTS module maintain a distribution list, and then have the DOC maintain another distribution list for the information it needs to send, Message Center provides a centralized facility for control of messages.
Messages within the message center can be individually enabled or disabled. If a message is disabled, then no messages will be sent, even if individuals or groups are subscribed to them. The system allows the creation of versions of the messages for different languages. Only one language version of the message can be enabled at a time. Obliquid does not pick the language.
Messages administration provides the ability to modify the template of the message that gets sent. A message is composed to two parts. One is a template which provides the basic text, and uses variables to indicate where each of the pieces of information the script supplies should go. You are free to rewrite the text template, put the variables anywhere you want. You can even choose to not display some of the information. Without program modifications, you cannot add aditional variables.
Normally, emails are sent as they are created. This behavior can be changed, and the Message center provides a page which allows you to manually request that the queued messages be sent. This is in case the automatic processes are not set to send an important message quick enough.
There are a few parameters in the system configuration which control the operation of the sending portion of the Message center.
Even if a message is enabled, it still needs somebody to deliver the message to. This is controlled through the Subscribe and Block features of the Message center. The actual email address that is used for the sending is obtained from the user information. There are four links for subscribing and blocking messages. These all perform the same basic function.
You can subscribe people to a message either by individual user ID, or by group ID. It may happen that an individual is subscribed to a particular message both by individual user ID, and because they are a member of a group that is subscribed. If that is the case, they will still only receive one copy of the message.
You can also block people who would normally receive a message from getting it. This is particularly useful if a person is a member of a group that gets a message, but really does not want to be bothered by that message.
A person can be added by the slot code when the message is queued. This is used for example, when a new person signs up, and we want to send them a welcome message.
How to customize Obliquid for your need. How to change the graphic appearance, and how to customize the access rights. Read this part also if you need to disable a module or a part of it.
Table of Contents
Table of Contents
Obliquid building blocks are pages and slots. A page is composed by placing one or more blocks (called slots) in a table. Each slot is a visual area on the screen interacting with a computer program. In the following sections you'll find the list of Obliquid pages and slot with their description
Module core, Author(s) Stefano Locati, Nicholas Vrtis
Base module supplying services to others: composes the web page, provides language and theme support
Table 10.1. Pages in module core
| Name | Description |
|---|---|
| home | Home |
| core_editpagegroup | List pages in a module. Each page can be edited, previewed or deleted and has a list of slots. |
| core_editpage | Edit a page where slots are shown on a grid 3x6 and can be moved, added or deleted |
| core_editslot | Edit a slot |
| core_showsource | View PHP source code |
| core_showtemplate | View Smarty template source |
| core_newpage | Add a new page |
| core_conflang | Enable or disable languages |
| core_confpagegroup | List modules and their pages |
| core_ewe | Visual HTML editor for newsletter body |
| core_eweedit | Visual HTML editor for slot templates |
| core_configparms | View or change modules parameters |
| core_credits | Credits for Obliquid project |
| core_demodata | Load demo data |
| core_txtedit | Text file editor, sends a message to people subscribed to core_edit on save |
| core_admtheme | Administration for graphic themes allowing to change name, sort order and to enable, add or delete themes |
| core_newmodule | Add a new module |
| core_pagecomment | Edit description for a page |
| core_slotcomment | Edit description for a slot |
| core_resethas | Reload your security |
| core_cron | Execute any pending task and it's usually called by some system batch job |
| core_listslots | List slots in a module |
Table 10.2. Slots in module core
| Name | Description |
|---|---|
| core/changelang | Change language with a drop down menu |
| core/changetheme | Change theme with a drop down menu |
| core/conflang | Enable or disable languages |
| core/confpagegroup | List modules and their pages |
| core/logo | Site logo that can be changed with sitelogo configuration parameter |
| core/configparms | View or change modules parameters |
| core/nav | Top icon bar |
| core/editpagegroup | List pages in a module: each page can be edited, previewed or deleted and has a list of slots. |
| core/editpage | Edit a page where slots are shown on a grid 3x6 and can be moved, added or deleted |
| core/pagedata | Modify page attributes |
| core/index | Core module side navigation menu |
| core/newslot | Add a new slot to a page, creating the necessary files if neeeded |
| core/newpage | Add a new page |
| core/demodata | Load demo data |
| core/editslot | Edit a slot, allowing to change its attributes |
| core/slotshow | Change fields of the slot, it works only for slots programmed to use them |
| core/showsource | View PHP source code |
| core/showtemplate | View Smarty template source |
| core/txtedit | Text file editor, sends a message to people subscribed to 'File modified' event |
| core/msgmodule | Obsolete |
| core/credits | Credits for Obliquid project |
| core/msgshow | Obsolete |
| core/admtheme | Administration for graphic themes allowing to change name, sort order and to enable, add or delete themes |
| core/cron | Execute any pending task and it's usually called by some system batch job |
| core/eweedit | Visual HTML editor for slot templates |
| core/home | Standard installation home page |
| core/listslots | List slots in a module |
| core/newmodule | Add a new module |
| core/pagecomment | Edit description for a page |
| core/slotcomment | Edit description for a slot |
| core/resethas | Reload your own security |
| core/slotparam | Obsolete |
Module user, Author(s) Stefano Locati, Nicholas Vrtis
Users, contacts and groups administration, security management
Table 10.3. Pages in module user
| Name | Description |
|---|---|
| user_groupadm | List of groups and links to pages to change groups details, list members, delete groups, change groups security |
| user_groupadd | Create a new group |
| user_groupmod | Modify name and description of a group |
| user_useradm | List of users and contacts applying the filters of slot user/userfilter |
| user_usernew | Create a new user or contact |
| user_usermod | Modify an existing user or contact |
| user_logout | Log yourself out and reset security |
| user_group_obj | Allow to assign security objects for a particular group |
| user_choose | Popup to choose a user applying the filters of user/userfilter |
| user_usermymod | Modify logged user own data |
| user_userview | Details of a user or a contact |
| user_security | List of all security objects of a type. For each security object there is a list of the groups that have access and a link to delete or create new security objects |
| user_securityobj | Create or delete security objects |
| user_securityasgn | Allow to assign groups to a security object |
| user_ops2groups | Show old operations assigned to each group. |
| user_specialasgn | Limited function page to assign groups to a single new object |
| user_usersignup | Allow visitors to register |
| user_meeting | List of lastest meetings of a person |
| user_export | Export users to Excel |
| user_statsess | Session statistics |
Table 10.4. Slots in module user
| Name | Description |
|---|---|
| user/login | Log yourself in the site |
| user/detailbox | View your own personal details |
| user/usermod | Create or modify a user or a contact |
| user/useradm | List of users and contacts applying the filters of slot user/userfilter |
| user/groupadm | List of groups and links to change groups details, list group members, delete groups, change groups security |
| user/index | User module side navigation menu |
| user/groupadd | Create a new group |
| user/groupmod | Modify name and description of a group |
| user/userfilter | Users search filter |
| user/usergroups | List groups a user belongs to and allows changing them |
| user/logout | Log yourself out and reset security |
| user/choose | Popup to choose a user applying the filters of user/userfilter |
| user/userview | Details of a user or a contact |
| user/users2groups | Obsolete |
| user/objs2groups | List of all security objects of a type. For each security object there is a list of the groups that have access and a link to delete or create new security objects |
| user/objadd | Create a new security object |
| user/group_obj | Allow to assign security objects to a group |
| user/groupassign | Allow to assign groups to a security object |
| user/export | Export users to Excel |
| user/statsess | Sessions statistics |
| user/meeting | List of lastest meetings of a person |
| user/groups2users | Groups and users counts |
Module cal, Author(s) Stefano Locati, Federico Carrara, Nicholas Vrtis
Calendar managing availabilities, call, recall, meetings, accounting entries and work sessions
Table 10.5. Pages in module cal
| Name | Description |
|---|---|
| cal_home | Calendar monthly view of events |
| cal_day | Calendar daily view of events |
| cal_addavail | Add an availability |
| cal_modavail | Modify an availability |
| cal_addcall | Add a call |
| cal_modcall | Modify a call |
| cal_modrecall | Modify a recall |
| cal_addmeeting | Add a meeting |
| cal_addmeetavail | Add a meeting starting from an availability |
| cal_modmeeting | Modify a meeting |
| cal_addaccount | Add an accounting entry |
| cal_modaccount | Modify an accounting entry |
| cal_accreport | Accountancy reports |
| cal_accdetail | Details of an account |
| cal_accperson | Account details for a single person |
| cal_addwork | Add a work session |
| cal_modwork | Modify a work session |
| cal_prjlist | Work reports by project |
| cal_prjdetail | Add or modify a project |
| cal_prjreport | Work report for a project |
| cal_wrkreport | Work report for a person |
| cal_c | Confirm or refuse meetings emails containing a security code, so it's safe to leave this slot assigned to everyone |
| cal_cache | Generate repeated events |
| cal_clean | Delete old availabilities |
Table 10.6. Slots in module cal
| Name | Description |
|---|---|
| cal/daywork | Daily work report by project and by person |
| cal/monthwork | Monthly work report by project and by person |
| cal/monthsmall | Compact monthly calendar |
| cal/index | Calendar module Side navigation menu |
| cal/filter | Menu to filter calendar events by type |
| cal/month | Calendar monthly view of events |
| cal/day | Calendar daily view of events |
| cal/addavail | Add or modify an availability |
| cal/addcall | Add or modify a call |
| cal/modrecall | Modify a recall |
| cal/addmeeting | Add or modify a meeting |
| cal/meetavail | Add a meeting starting from an availability |
| cal/meetingslist | List meetings between two persons and may send a confirmation email |
| cal/confirm | Confirm or refuse meetings emails containing a security code, so it's safe to leave this slot assigned to everyone |
| cal/addaccount | Add or modify an accountancy entry |
| cal/accreport | Accountancy reports |
| cal/accdetail | Details of an account |
| cal/accperson | Account details for a single person |
| cal/addwork | Add or modify a work session |
| cal/prjlist | Work reports by project |
| cal/prjdetail | Add or modify a project |
| cal/prjreport | Work report for a project |
| cal/wrkreport | Work report for a person |
| cal/cache | Generate repeated events |
| cal/clean | Delete old availabilities |
Module news, Author(s) Stefano Locati, Nicholas Vrtis
Multilingual news publishing system with a simple security system allowing to restrict topics. Articles are grouped into topics, each article can be in multiple languages and has a title, a subtitle a html body and attached files or pictures
Table 10.7. Pages in module news
| Name | Description |
|---|---|
| news_adm | News administration: list of topics with security restrictions applied |
| news_upload | News administration: popup to upload a file into an article |
| news_cat | News administration: create or modify a topic |
| news_list | News administration: list of articles to modify in a topic |
| news_item | News administration: create or modify an article |
| news_edit | News administration: edit an article text body |
| news_viewcats | List news topics with security restrictions applied |
| news_viewlist | List articles within a topic |
| news_viewitem | View a news article |
| news_download | Download a file attached to an article |
Table 10.8. Slots in module news
| Name | Description |
|---|---|
| news/adm | News administration: list of topics with security restrictions applied |
| news/upload | News administration: popup to upload a file into an article |
| news/cat | News administration: create or modify a topic |
| news/list | News administration: list of articles to modify in a topic |
| news/item | News administration: create or modify an article |
| news/viewcats | List news topics with security restrictions applied |
| news/viewlist | List articles within a topic |
| news/viewitem | View a news article |
| news/edit | News administration: edit an article text body |
| news/download | Download a file attached to an article |
Module doc, Author(s) Stefano Locati, Nicholas Vrtis
Document management system with advanced security
Table 10.9. Pages in module doc
| Name | Description |
|---|---|
| doc_home | Main page providing document search |
| doc_detail | View details of a document |
| doc_admcat1 | Manage category 1 items |
| doc_admcat2 | Manage category 2 items |
| doc_admcat3 | Manage category 3 items |
| doc_admdoc_type | Manage document type items |
| doc_admlang | Manage language list for documents |
| doc_notapproved | List of documents containing at least one object not approved yet |
| doc_moditem | Modify a document and may send a message to people subscribed to 'New object uploaded' event or to 'Document changed' event |
| doc_additem | Add a document and may send a message to people subscribed to 'New object uploaded' |
| doc_appritem | Approve or not an object and sends a message to people subscribed to 'Object approved' or to 'Object NOT approved' events |
| doc_seclistcats | First screen to manage security: list all 'category 1' items |
| doc_seclisttypes | Second screen to manage security: list 'document type' and 'category 1' combinations and groups allowed |
| doc_seclistgu | Group and user permissions for a 'category 1' and 'document type' combination |
| doc_secadc | Change operations for a group or a user on a specific 'category 1' and 'document type' combination. It can also be used to change operations for a group or a user on a specific document |
| doc_seclistitems | List all items with specific security for a 'category 1' and 'document type' combination |
| doc_checkfiles | Verify consistency |
Table 10.10. Slots in module doc
| Name | Description |
|---|---|
| doc/home | Search form |
| doc/detail | View details of a document |
| doc/search | Document list resulting from a search made with doc/home search form |
| doc/index | Documentation module side navigation menu |
| doc/admcat1 | Manage category 1 items |
| doc/admcat2 | Manage category 2 items |
| doc/admcat3 | Manage category 3 items |
| doc/admdoc_type | Manage document type items |
| doc/admlang | Manage languages for documents |
| doc/notapproved | List of documents containing at least one object not approved yet |
| doc/moditem | Add or modify a document, may send a message to people subscribed to 'New object uploaded' event or to 'Document changed' event |
| doc/appritem | Approve or not an object and sends a message to people subscribed to 'Object approved' or to 'Object NOT approved' events |
| doc/seclistcats | First screen to manage security: list all 'category 1' items |
| doc/seclisttypes | Second screen to manage security: list 'document type' and 'category 1' combinations and groups allowed |
| doc/seclistgu | Group and user permissions for a 'category 1' and 'document type' combination |
| doc/secadc | Change operations for a group or a user on a specific 'category 1' and 'document type' combination. It can also be used to change operations for a group or a user on a specific document |
| doc/seclistitems | List all items with specific security for a 'category 1' and 'document type' combination |
| doc/noattach | List all documents without any attached object |
| doc/checkfiles | Check for existence and correct size of files |
| doc/fixapprove | Recomputes the approved flag for all documents |
Module msg, Author(s) Stefano Locati
Workflow email management
Table 10.11. Pages in module msg
| Name | Description |
|---|---|
| msg_home | Message module main page showing some statistics |
| msg_textadm | Message administration providing a list of event messages |
| msg_textmod | Modify a message subject and body |
| msg_sendperson | Manage a list of persons subscribed to specific events emails |
| msg_blockperson | Manage a list of persons who won't receive specific events emails |
| msg_sendgroup | Manage a list of groups subscribed to specific events emails |
| msg_blockgroup | Manage a list of persons who won't receive specific events emails |
| msg_personadd | Add a person to either the send or the block list |
| msg_groupadd | Add a group to either the send or the block list |
| msg_runqueue | Send a batch of messages waiting in the queue |
Table 10.12. Slots in module msg
| Name | Description |
|---|---|
| msg/home | Message module main page showing some statistics |
| msg/index | Side navigation menu |
| msg/textadm | Message administration providing a list of event messages |
| msg/textmod | Modify a message subject and body |
| msg/sendperson | Manage a list of persons subscribed to specific events emails |
| msg/blockperson | Manage a list of persons who won't receive specific events emails |
| msg/sendgroup | Manage a list of groups subscribed to specific events emails |
| msg/blockgroup | Manage a list of persons who won't receive specific events emails |
| msg/personmod | Add a person to either the send or the block list |
| msg/groupmod | Add a group to either the send or the block list |
| msg/runqueue | Send a batch of messages waiting in the queue |
Module posts, Author(s) Nicholas Vrtis, Stefano Locati
Posts and newsletter management
Table 10.13. Pages in module posts
| Name | Description |
|---|---|
| posts_admlistcats | POSTS administration category selection list |
| posts_admcatadc | POSTS category add, delete, change |
| posts_admlistitems | POSTS item selection list |
| posts_admitemadc | POSTS item add, delete, change |
| posts_admlistobjs | POSTS object selection list |
| posts_admobjadc | POSTS object add, delete, change |
| posts_admviewobjs | Special version to allow administrator to view an object page |
| posts_viewcats | Main entry for POSTS user viewing |
| posts_viewitems | User selection list of items in a category |
| posts_viewobjs | User object display page.. note same slot in three locations |
| posts_download | User download of attached POSTS file |
| posts_showpicture | Popup to show full size picture from POSTS image |
| posts_admitemapv | Set approved flag for an item |
| posts_admobjapv | Set approved flag for an object |
| posts_admsend | Send (test or full) Newsletter item |
| posts_admsendconf | Ask for confirmation before sending a newsletter |
| posts_statscat | Newsletter statistics: list of categories |
| posts_statsitems | Newsletter statistics: list of newsletters in a category |
| posts_statsnewsl | Newsletter statistics: statistics for a single newsletter |
| posts_view | Allow to view a newsletter image updating the statistics |
Table 10.14. Slots in module posts
| Name | Description |
|---|---|
| posts/admlistcats | Main entry for posts administration, displaying a list of all categories |
| posts/admcatadc | Add, delete, or change information about a post category |
| posts/admlistitems | Display a list of all items in a category and links to changes. |
| posts/admitemadc | Add, delete, or change information about a post item |
| posts/admlistobj | Display a list of all objects in an item and links to changes. |
| posts/admobjadc | Add, delete, or change information about a post object |
| posts/viewcats | Displays a list of all categories |
| posts/viewitems | Display a list of all items in a category |
| posts/viewobjs | Display objects for an item in the slot requested. What is shown depends on what type of object it is |
| posts/download | Download an attach item file to the user |
| posts/showpicture | Display the full size picture from a photo object in a new window |
| posts/admitemapv | Set the approved flag for a particular item and return to admlistitems |
| posts/admobjapv | Set the approved flag for a particular object and return to admlistobjs |
| posts/admsend | Send either the test or full newsletter |
Module dev, Author(s) Stefano Locati
Tools for developers
Table 10.15. Pages in module dev
| Name | Description |
|---|---|
| dev_doc | Project documentation |
| dev_dbdoc | Generate Database documentation from Metabase XML common configuration |
| dev_langsearch | Search in compendium and system messages |
| dev_dumpdb | Show DB table information, create config/*.tpl files, dump a table to screen |
| dev_resettable | Reset table with default data |
| dev_extramsg | Write a PHP file with database messages to be translated |
| dev_translist | Translation work area (experimental) |
| dev_transsave | Save translations to file (experimental) |
| dev_rndtrans | Translate a sentence (experimental) |
| dev_localdata | View local field descriptions |
| dev_mergetable | Merge tables step 1 |
| dev_mergetable2 | Merge tables step 2 |
| dev_sequence | Check database sequences |
| dev_uploadpo | Load PO translation files |
| dev_checkdata | Check database consistency |
| dev_checkdb | Check database structure |
| dev_components | Write components chapter for the manual |
| dev_langencoder | Encode multiple translations in one string |
Table 10.16. Slots in module dev
| Name | Description |
|---|---|
| dev/dbdoc | Generate Database documentation from Metabase XML common configuration |
| dev/extramsg | Write a PHP file with database messages to be translated |
| dev/translist | Translation work area (experimental) |
| dev/doc | Project documentation |
| dev/resettable | Reset table with default data |
| dev/transsave | Save translations to file (experimental) |
| dev/rndtrans | Translate a random sentence |
| dev/localdata | View local field descriptions |
| dev/index | Side navigation menu |
| dev/dumpdb | Show DB table information, create config/*.tpl files, dump a table to screen |
| dev/langencoder | Encode multiple translations in one string |
Module prj, Author(s) Nicholas Vrtis
Project management
Table 10.17. Pages in module prj
| Name | Description |
|---|---|
| prj_activityadc | Manage activity types |
| prj_mandatoryadc | Manage mandatory phases |
| prj_useradm | Users administration |
| prj_usermod | Edit user info |
| prj_addbid1 | Start a new project |
| prj_basicac | Basic information |
| prj_phaseac | Phase information |
| prj_supplierac | Supplier information |
| prj_costac | Cost information |
| prj_custbids | Project list for an organization |
Table of Contents
One of the most common questions I am asked from people approaching to Obliquid, is how deeply the graphic may be customized. In fact, if you build your own theme, it's possible to compose your page in a custom way. Once you are satisfied with your own theme you may want to lock the site with your theme by disabling core/changetheme slot.
Themes are plug-in skins that allow to change the appearance of a web site. To achieve this result some rules must be followed in order to create a theme that can be interchanged with others.
In practice a theme is composed of a few Smarty templates, a stylesheet and images.
Obliquid makes extensive use of templates. Templates are a way to separate HTML from PHP code and are designed to look as much like regular HTML as possible. The HTML code is displayed by the browser normally, while some special codes are substituted by the Smarty template engine. The most simple code is the one for variable substitution. A variable inside a Smarty template is a placeholder that looks like this {{$variable}}. From a PHP script it's possible to substitute the variable with any value, including another template.
Obliquid core implements a three level template system. Three levels means that templates are substituted inside templates which in turn are substituted inside the top level templates. The top level template is called frame level and corresponds to the outer layout of a served page. It's possible to have many different frames templates for different pages, or always reuse the same one for every page. The second level is the block level and is used to put some window like border to the elementary content. This level is not mandatory and may be bypassed. The third level is the slot level and is used to deliver the content and the functionality of a simple part of an application. A slot may or may not have an associated PHP script that delivers dynamic functionality.
The frame level corresponds to the outer layout of the served page. The frame is a template and may be manipulated directly using the handle $_obweb->smframe (created for you by obliquid core). The {{$page_title}} variable can be setted through configuration parameters. {{$metadata}} variable can be used to add any content in the head section, tipically metadata tags.
A frame normally contains other variables. In a custom approach you can choose whatever name you want for them. Using a theme-compatible approach the variables are called {{$left1}}, {{$center1}}, {{$right1}}, {{left2}}, ..., {{$right6}}. Themes allows to have a one, two or three columns layout. It's also possible to have different sections with a different number of columns. You can have up to six sections.
For example we may put a logo on the left and a banner on the remaining space in the first section using {{$left1}} and {{$center1}}, in the second section we have a menu bar that takes all the width by using a {{$center2}}, in the third section we have only a date on the right using {{$right3}}, in the fourth section a three column layout with many {{$left4}}, {{$center4}} and {{$right4}} blocks that gets piled stacked from top to bottom, in the fifth section a copyright notice on the right using {{$right5}}. We decide not to use the sixth section.
{{$metadata}}
{{$page_title}}
+-------------+--------------+--------------+
| {{$left1}} | {{$center1}} | {{$right1}} |
+-------------+--------------+--------------+
| {{$left2}} | {{$center2}} | {{$right2}} |
+-------------+--------------+--------------+
| {{$left3}} | {{$center3}} | {{$right3}} |
+-------------+--------------+--------------+
| {{$left4}} | {{$center4}} | {{$right4}} |
+-------------+--------------+--------------+
| {{$left5}} | {{$center5}} | {{$right5}} |
+-------------+--------------+--------------+
| {{$left6}} | {{$center6}} | {{$right6}} |
+-------------+--------------+--------------+
A frame conceptual schema.
A block is the second level of our three level template system, it's used to put windows like decorations to the bare content. For each single slot (the inner content), is possible to decide if to use an outer block or not. It's also possible to choose between different styles of block. Blocks are templates and they may be manipulated directly using the handle $_obweb->smblock (created for you by obliquid core). We can choose to have a strongly emphasized titled window (title_em), a simple titled window (title), a bordered window with no title (border) or no decorations (none). Any of these types, except none corresponds to a filename in the template directory.
To summarize a bit in a theme approach is mandatory to have a frame.tpl file for the outer frame and title_em.tpl, title.tpl, border.tpl for the blocks. In a custom approach, the block level may be skipped (using none), or may be used with custom theme filenames or by introducing new block files.
title_em.tpl and title.tpl have a mandatory title and a content section, and may have a caption and a button section. The button section is for adding some small graphic buttons for extra functions like an help button. The slot is automatically associated to the content section. Other sections have to be manipulated manually from the slot PHP code.
+--------------------------------+
| {{$title}} {{$button}} |
+--------------------------------+
| {{$content}} |
+--------------------------------+
| {{$caption}} |
+--------------------------------+
At the third and last level of the templates system there are slots. Slots are templates and they may be manipulated directly using the handle $_obweb->smslot (created for you by obliquid core). Their content and structure is absolutely custom.
To implement a theme CSS, the best thing is to modify a CSS for an existing approved theme. The public styles are the following:
pagebody: to be inserted in the body tag titlebig: big titles titlestandard: standard titles titlemini: small titles or subtitles textstandard: normal text textmini: smaller text textform: form elements tablemain: to be inserted in the table tags tableheader: to be inserted in td tags holding a title tablebody: to be inserted in td tags holding content passed: text to notify a successful event failed: text to notify a failed event enabled: text to convey that something is enabled disabled: text to convey that something is disabled picture: to be inserted in img tags
If you understood the description about themes in the previous sections, you are now ready to create your own. Don't be afraid to experiment, and if you reach noticeable results feel free to contact the Obliquid team.
Copy one of the existing themes in common/theme directory, inside local/theme directory. To avoid yourself problems, choose a directory name composed only by lowercase a-z letters and the underscore. For example I create a directory named floating inside local/theme, then I choose a theme to start from, for example obliquid because it's simple and so I copy content from common/theme/obliquid to local/theme/floating.
The first file to edit is frame.tpl, as explained before it's the outer layout of a page. The first thing to change here is the stylesheet. Instead of pointing to common/theme/obliquid/style.css, make it point to local/theme/floating/style.css.
<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN">
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
<title>{{$page_title}}</title>
<link rel="stylesheet" type="text/css" href="common/theme/obliquid/style.css">
<script language="JavaScript">
<!--
function popupErr(err_msg) {
From here make your changes to any file in this directory. Pay attention to path pointing to your starting theme, make sure to fix them all.
The best thing is to test your changes early, so you have to activate your custom theme. To do so click on Configure site and then on Manage theme. There you can add a new theme by specifying the theme name, the relative path, the order in which it has to appear in the list, and if it has to be enabled or not.
A serious installation may need more than a custom presentation. Some parts could be changed, some others written from scratch. If your modifications could be of general interest consider discussing them on the forum, and eventually joining the team, but if your modifications are very custom, you have to implement them yourself. Our team is doing everything possible to allow you to extend Obliquid, while still allowing to upgrade it when the next version becomes available.
Table of Contents
Table of Contents
What you need to know to be able to modify Obliquid proficiently. This documentation is still a work in progress. In case anything is not explained clearly or is not explained at all, ask to the forum.
We tried to minimize the number of variables in the global environment. Some of the global variables are provided through $_obweb, an instance of obliquidweb class generated by obliquid core.
Other variables are instead available through $_SESSION, the standard PHP array with session data
Obliquid uses Metabase as database astraction layer. Metabase is better than many other database access layers, because it manages the database structure with XML files and is able to talk to many different vendors DBMS.
Despite this, Obliquid supports only MySQL, and even if the database structure could be easily installed on other DBMSs, the queries will simply not work. Sometimes in the future the team will probably decide to support a new database too. This will mean to check every query, and will also make releasing upgrade packages more difficult: that's why it will probably happen after version 1.0 is released.
A Metabase instance is already created for you by Obliquid framework in $_obweb->mb. Metabase has extensive documentation and a tutorial. Below you will find some examples for the most used operations.
Example 12.1. Metabase Query method
In this example, we are deleting a row from news_ctext, specified by cat GET parameter. The method Query is used because we don't have to fetch any result from this query. sprintf is used because a GET parameter can be easily manipulated by a user to contain anything.
$sql="DELETE FROM ".$_obweb->tprefix
.sprintf("news_ctext WHERE id_news_cat=%d", $_GET["cat"]);
$success=$_obweb->mb->Query($sql);
if (!$success) echo $_obweb->mb->Error();
Example 12.2. Metabase GetSequenceNextValue method
In this example, we call GetTextFieldValue method manually to prepare the text values. Then we check wether catid is set to new or to a numeric value. If catid is new we do an INSERT. To find the new id to be inserted, we call the method GetSequenceNextValue: the new id will be in $catid variable. For this method to work a sequence has to be defined on the table.
//Make sure all text is fit to be inserted
$lang = $_obweb->mb->GetTextFieldValue($_POST["lang"]);
$title = $_obweb->mb->GetTextFieldValue(htmlspecialchars($_POST["title"]));
$desc = $_obweb->mb->GetTextFieldValue(htmlspecialchars($_POST["desc"]));
$rstd = $_obweb->mb->GetTextFieldValue($_POST["rstd"]);
$aa = $_obweb->mb->GetTextFieldValue($_POST["aa"]);
$ob = $_obweb->mb->GetTextFieldValue($_POST["ob"]);
if ($_POST["catid"]=="new") { //Finally.. see if new or update
$_obweb->mb->GetSequenceNextValue($_obweb->tprefix."posts_cat", $catid);
$sql = sprintf("INSERT INTO %sposts_cat VALUES (%d, %s, %s, %s, %s, %s, %s, '', %d)",
$_obweb->tprefix, $catid, $lang, $title, $desc, $rstd, $aa, $ob, $ord);
} else {
$catid = $_POST["catid"];
$sql = sprintf("UPDATE %sposts_cat SET lang=%s, title=%s, description=%s, restricted=%s, autoapprove=%s, ordby=%s, ord=%d WHERE id_posts_cat=%d",
$_obweb->tprefix, $lang, $title, $desc, $rstd, $aa, $ob, $ord, $catid);
}
$_obweb->mb->Query($sql);
Example 12.3. Metabase QueryField method
Here we find the number of unsent events. This is a simple select query with just a field to retrieve, so we use the method QueryField. Variable $total will be filled with the query result.
//number of total unsent events
$sql="SELECT count(*) FROM ".$_obweb->tprefix."msg_queue WHERE sent='N'";
$success=$_obweb->mb->QueryField($sql, $total);
if (!$success) echo $_obweb->mb->Error();
Example 12.4. Metabase QueryRow method
Most of the times a query will fetch more then a field at a time. We can use QueryRow when only a row of results is expected.
//Get the title and description of the category with this language
$sql="SELECT title, body FROM ".$_obweb->tprefix
.sprintf("news_ctext WHERE id_news_cat=%d AND lang = '%s'",
$_GET["cat"], $catlang);
$_obweb->mb->QueryRow($sql, $catinfo);
//$catinfo[0] contains the title, and $catinfo[1] the description
Example 12.5. Metabase QueryAll method
This query gets a list of post objects. QueryAll method gets the whole result set in a matrix stored in $objs variable.
//Get the list of objects
$sql = "SELECT id_posts_object, object_name, object_type, ord, location, approved FROM "
.$_obweb->tprefix."posts_object WHERE id_posts_item='".$_GET["id"]
."' ORDER BY location, ord";
$_obweb->mb->QueryAll($sql, $objs);
This variable is then passed to a Smarty template that displays the results.
{{foreach from=$objs item=obj}}
<tr>
{{section loop=$obj name=i start=1}}
<td class="tablebody">{{$obj[i]}}</td>
{{/section}}
</tr>
{{/foreach}}
$_obweb->mb->GetBooleanFieldValue(true) Convert a boolean value into a DBMS specific format that is suitable to compose query statements.
![]() | Don't use your own database connections |
|---|---|
They will make your application a lot harder to maintain, and in core Obliquid programming it's wrong | |
HTML form building may pose problems for unesperienced people because there are many little and subtle things to know; even experienced people may find confortable to have a more consistent interface. Since long ago I've trying to build a class that would help that process. The idea actually came from a guy that was working for us at the time. Nothing new, there are many classes to build forms, but not even one in the way I wanted, at the time.
My form class had to help to build form controls, to retrieve their value and to build database queries to give the best efficiency and to reduce bugs. It started to support MySQL, then we had to do a job with Oracle and so we expanded it to handle Oracle too. After starting the free Obliquid project I switched to Metabase to be able to support different databases without having to write special code for any of them.
The most basic way to use the db_form class is without the database: even if this is a rare case it will help to grasp the concepts in a first step. I usually form controls in a form array that I call $frm that I then pass to the Smarty template. In this example I simply build a form with the available controls.
getTextInput method returns a text box input, the first parameter name is the html variable name that will be stored in $_POST["name"] after submitting the form. All other parameters are optional, but typically the SIZE would be specified, as the CSS class "textform". Having a common CSS class helps: if we want to change the font sizes for forms in a theme we can do by modifying a single value.
getTextArea method returns a text area. In HTML forms the basic syntax of a textArea is different from the syntax of a text box, while in db_form such difference disappear. The first parameter of the method is, as usual, the variable name, description in this case; after this there is an optional array of additional parameters.
getDateInput helps to input dates: as always the first parameter is the variable name, in this case sdate and the other parameters are optional, the start year is the first optional parameter 1998 in our example, which is also the default, the second parameter is the end year, by default it's the current year, but here we defined it to be two years later date("Y")+2, as last parameter the textform style is applied.
getCheckbox returns a HTML checkbox. As always the first parameter is the variable name ( restricted ) and it's the only one used in this example.
getRadio returns a radio button, the first parameter is th variable name, in this case recur. As you can notice, there are two radio buttons with the same name, and it means they are mutually exclusive.
getSubmit returns a submit button: the first parameter is the variable name, which value is usually not considered, since it's its label.
PHP excerpt
$dbf =& new db_form();
$frm["name"]=$dbf->getTextInput("name",
array("CLASS" => "textform", "SIZE" => "25"));
$frm["description"]=$dbf->getTextArea("description",
array("CLASS" => "textform", "ROWS" => "3", "COLS" => "45"));
$frm["moddate"]=$dbf->getDateInput("moddate", 1998, date("Y")+2,
array("CLASS" => "textform"));
//radio buttons must start with a default, for the html specification
$frm["author_no"]=$dbf->getRadio("author", "");
$frm["author_st"]=$dbf->getRadio("author", "Stefano");
$frm["author_ni"]=$dbf->getRadio("author", "Nick");
$frm["enable"]=$dbf->getCheckbox("enable");
$frm["version"]=$dbf->getSelect("version", array(array("1.0", "stable"),
array("beta", "beta"),
array("alpha", "alpha")
));
$frm["submit"]=$dbf->getSubmit("submit", _l("Save"), array("CLASS" => "textform"))
.$dbf->getHidden("action", "exampleform");
$_obweb->smslot->assign(array("frm" => $frm));
Smarty template
<form method="post" NAME="exampleform">
Module name: {{$frm.name}}<br><br>
Description: {{$frm.description}}<br><br>
Last modified: {{$frm.moddate}}<br><br>
Author: Not chosen {{$frm.author_no}}
Stefano {{$frm.author_st}}
Nick {{$frm.author_ni}}<br><br>
Enabled: {{$frm.enable}}<br><br>
Version: {{$frm.version}}<br><br>
{{$frm.submit}}
</form>
In this section I will explain how to retrieve values from the form. This values may be stored in database, or they may go through validation checking. I will keep on extending on the previous example, so we introduce concepts bit by bit, the code added is emphasised.
Form values can be read with the method getValue of the class db_form, they also can be read with $_POST[] php variable, but some of them are more confortably fetched by the method because of added fancy processing. This is true for dates and checkboxes
An example output, echo are used here for testing purposes. Normally echo are not used inside Obliquid because any result is assigned to Smarty templates, but they are a convenient way to test something fast.
test | test meaningless words | meaningless words 2002-04-26 | dateinput Nick | Nick 0 | beta | beta
$dbf =& new db_form();
if ($_POST["action"]=="exampleform") {
//we are here, so the form was posted
$dbf->parseForm(); //parse the form and reassign it back to controls
//any variable can be accessed with $dbf->getValue()
echo $dbf->getValue("name")." | ".$_POST["name"]."<br>";
echo $dbf->getValue("description")." | ".$_POST["description"]."<br>";
echo $dbf->getValue("moddate")." | ".$_POST["moddate"]."<br>";
echo $dbf->getValue("author")." | ".$_POST["author"]."<br>";
echo $dbf->getValue("enable")." | ".$_POST["enable"]."<br>";
echo $dbf->getValue("version")." | ".$_POST["version"]."<br>";
}
$frm["name"]=$dbf->getTextInput("name",
array("CLASS" => "textform", "SIZE" => "25"));
$frm["description"]=$dbf->getTextArea("description",
array("CLASS" => "textform", "ROWS" => "3", "COLS" => "45"));
$frm["moddate"]=$dbf->getDateInput("moddate", 1998, date("Y")+2,
array("CLASS" => "textform"));
//radio buttons must start with a default, for the html specification
$frm["author_no"]=$dbf->getRadio("author", "");
$frm["author_st"]=$dbf->getRadio("author", "Stefano");
$frm["author_ni"]=$dbf->getRadio("author", "Nick");
$frm["enable"]=$dbf->getCheckbox("enable");
$frm["version"]=$dbf->getSelect("version", array(array("1.0", "stable"),
array("beta", "beta"),
array("alpha", "alpha")
));
$frm["submit"]=$dbf->getSubmit("submit", _l("Save"), array("CLASS" => "textform"))
.$dbf->getHidden("action", "exampleform");
$_obweb->smslot->assign(array("frm" => $frm));
db_form can also handle uploaded files. The first thing to remember is that the form METHOD should be “POST” and that the ENCTYPE should be “multipart/form-data”.
<form enctype="multipart/form-data" method="post">
{{$frm.image}}
{{$frm.submit}}
</form>
if ($_POST["action"]=="exampleupload") {
$dbf->parseForm();
//the following lines are here to document the available values
$original_name=$dbf->getFormValue("image");
$tmp_name=$dbf->getFormValue("image_tmp_name");
$size=$dbf->getFormValue("image_size");
$mime=$dbf->getFormValue("image_mime");
//test if a file was uploaded or not
if ($dbf->is_uploaded_file("image")) {
move_uploaded_file($tmp_name, $final_destination);
}
}
$dbf =& new db_form();
$frm["image"]=$dbf->getFileInput("image", array("CLASS" => "textform"));
$frm["submit"]=$dbf->getSubmit("submit", _l("Save"), array("CLASS" => "textform"))
.$dbf->getHidden("action", "exampleupload");
$_obweb->smslot->assign(array("frm" => $frm));
Available since Obliquid 0.7
db_form has also the ability to help with simple query creation. In order to do so, it must know the structure of a table that is stored inside tabledesc Obliquid table. Before switching to Metabase db_form class was fairly complex, in order to handle many db datatypes, and when a datatype not used before was found it stopped to work. Now these problems are solved because Metabase has just a few simple datatypes.
Further in order to support the creation of the next value a sequence must exist on the table. A sequence is a small table, added to Metabase XML table definition file. For example:
<sequence>
<name>{{$tprefix}}module</name>
<start>1</start>
<on> <table>{{$tprefix}}module</table>
<field>id_module</field>
</on>
</sequence>
To build an insert query you need to create a new Id and call executeSqlInsert method.
$dbf =& new db_form();
if ($_POST["action"]=="add_record") {
//the form was posted for insert
$dbf->setDbConnection($_obweb->mb);
$dbf->setTable("module", $_obweb->tprefix); //setTable clears form values!
$dbf->parseForm(); //parse the form and reassign it back to controls
$dbf->newId(); //creates a new id
$dbf->executeSqlInsert(); //executes an insert query
}
//here the form will be built as explained in the previous sections
To build an update query you need to fetch the existing record from database with fetch method, and then call executeSqlUpdate method.
$dbf =& new db_form();
$dbf->setDbConnection($_obweb->mb);
$dbf->setTable("module", $_obweb->tprefix); //setTable clears form values!
//fetches the current record for the update or the form below
$dbf->fetch($_GET["id"]);
if ($_POST["action"]=="mod_record") {
//the form was posted for update
$dbf->parseForm(); //parse the form and reassign it back to controls
$dbf->executeSqlUpdate(); //executes an insert query
}
//here the form will be built as explained in the previous sections
This part needs some more explanations: the fetch method stores the record in internal private variables. Just after a fetch, I can get the value for author with $dbf->getValue("author"), but after a parseForm, the same instruction will return the value coming from the form. The reason for this apparently strange behaviour is that form values have higher priority, and this is a design feature of db_form. In this way if any of the column existing in the table is not added in the form it will be preserved, because when a form value is not found, the db value will be returned instead.
In some cases you need to explicitly refer to form values or db_values, this is possible with the methods getFormValue (or using PHP $_POST array) and with getDbValue.
Every web page calls index.php file in the main directory. This is because this script sets up the environment, opens a connection to the db, includes classes that will be always used and so on. Besides this it implements the main processing loop assembling a page from its slots, and provides basic security.
Pages are assembled by their slot pieces, as defined in pagexml directories. Since Obliquid 0.6.0, there are two such directories, one in the common directory tree and one in the local directory tree: so we have common/pagexml and local/pagexml. Pages can be defined both in the common tree or in the local tree, but when a page with the same name is found in both the common and the local tree, the local tree takes precedence; in fact this is the way to redefine (object oriented programmers may like the term overload) an existing page to make your own changes. Using the site configuration interface, a page will in a locked state, with no changes allowed until you push the button Copy to local to modify. By pushing this button, a page definition will be copied from common/pagexml to local/pagexml, for example the home page would be copied from common/pagexml/core/home.xml to local/pagexml/core/home.xml.
Let's look in more detail to the directory structure inside a pagexml directory first. There we can find a list of directories, one directory for each module. There is a simple rule for naming a page: <module name>_<short name>. For example the page named news_item is from module news and has item as short name. This page will be saved either in common/pagexml/news/item.xml or in local/pageml/news/item.xml. The only exception to this rule is for the page named home, that is part of module core, but doesn't require the core_ prefix.
Each page definition is a little XML that explains how the page is going to be built starting from the slot bricks. The format is not complicated, but there is no need to know it, since the Configure site function will change these files for you.
If you are curious, or want to know more about Oliquid, I give some basic explanations here. The first line in this example is the XML definition line and must always exist. The second line has a PAGE element: the NAME attribute of this element defines the page name, and should match the name coming from the file path (news/item.xml -> news_item). The relative url for this page is '/index.php?page=news_item'. Pages names are used in the url, and stored in XML, and for this reason it's advised to stick to a conservative set of characters (lowercase letters a-z, and underscore _).
<?xml version="1.0" encoding="UTF-8"?> <PAGE NAME="news_item" TPL="common" FRAME="frame" GROUP="news"> <SLOT NAME="core/nav" PHP="common" TPL="common" POSITION="center1" BLOCK="none"/> <SLOT NAME="core/changelang" PHP="common" TPL="common" POSITION="left2" BLOCK="title"/> <SLOT NAME="news/item" PHP="common" TPL="common" POSITION="center2" BLOCK="title_em"/> <SLOT NAME="news/viewitem" PHP="common" TPL="common" POSITION="center2" BLOCK="title"/> </PAGE>
![]() | Previous format, valid until Obliquid 0.5.0 included |
|---|---|
Pages were defined in 'local/configs/config.xml' in a single XML file. This file had a PAGE element for each page type, and was not that easy to upgrade, because if modified, either by hand, or with Obliquid configuration, an upgrade needed the tedius task to find differencies manually between the new config.xml file and the existing one. Another concern that has been addressed with the new syntax is about the size of the file (reaching 600 lines), which made XML dom parsing slow. The syntax of the PAGE element has not been modified (Obliquid 0.6.0). | |
Every page is composed of slots which are the elementary blocks. The slots that a page type includes are defined in pagexml in the SLOT tags as children of that PAGE tag.
Slot name is in relationship with its file name. In this example the NAME attribute has value core/logo and since TPL is common, the template for this slot will be looked in common/templates/core/logo.tpl. The directory has the same name as the module name, in this case core.
In this example there is no PHP script associated to this template (a simple static template), and thus PHP attribute is set to 'NONE'. The POSITION attribute specifies where the slot template should be shown in the frame as described in themes. The BLOCK attribute, instead defines the decoration to be applied to the slot, this is also described in the themes document.
<SLOT NAME="core/logo" TPL="common" PHP="none" POSITION="left2" BLOCK="title"/>In this second example there is also a PHP script associated to the template since PHP attribute value is common. This means that a PHP script located in common/pages/core/nav.php will be executed and will be able to address the common/templates/core/nav.tpl template.
<SLOT NAME="core/nav" PHP="common" TPL="common" POSITION="center1" BLOCK="none"/>This slot defines a system wide menu that changes dinamically according to the permissions of the logged user. It is reasonable to change this menu from site to site to insert new local functionalities or the like. To accomplish this result I could modify the common template and php file but this would not be advisable because an upgrade would overwrite the common files. Moreover we would like to see easily which modifications we made to implement a particular site and this approach would make this more difficult.
If we want to simply change the table in the php code, for adding a new icon, or for changing all of them we can define the PHP attribute as local. In this case the script would be loaded from local/pages/core/nav.php.
<SLOT NAME="core/nav" PHP="local" TPL="common" POSITION="center1" BLOCK="none"/>In other case we may also want to alter the templates and we can do this by defining TPL attribute as local: in this case our smarty template would be loaded from local/templates/core/nav.tpl. Of course any combination of 'common', 'local' and 'none' for PHP and TPL is valid.
While it is a good rule to have a PHP script named in the same way as the template, in some particular cases you may also want to call a PHP script and a template with different names. This is possibile and can be achieved by using NAME_PHP and NAME_TPL attributes instead of NAME.
A slot script should only define functions. It should not execute any code when it is loaded. This will allow the system to check the security authorization of the user before any slot code is executed. The default function that the system will call after the code is loaded is the name of the slot, with the slash replaced by an underscore, and an underscore added to the end. As an example, the system will call core_nav_() as the main function for the core/nav slot.
You can also define a different function to be called for a slot. Use the FUNCTION parameter in the SLOT definition.
Each slot is loaded with a require_once statement. So it will be loaded only once, no matter how many times the slot is defined in a page. The defined function will be called for each slot entry though.
The simple approach would be to simply write the script in the global scope. Unfortunately this can bring to variable names clashing. If the same variable name is used by two slots in the same page, the second slot would see the variable of the first slot. This may cause misterious bugs and so this approach is not allowed by Obliquid security system.
<?php
...
$_obweb->smslot->assign("templatevar", $templatevar);
?>
Generally slot script are short: this is an advantage of this architecture that divides the page in its elements. Even if a slot has to deliver complicated functionality it is better to put this in a separate class and keep the script short.
<?php
function core_nav_() {
global $_obweb;
...
$_obweb->smslot->assign("templatevar", $templatevar);
}
The function name must be modulename_slotname_() for Obliquid to be able to call it. Also notice that there is no PHP end tag, to avoid any headers already sent problem, caused by extra blank lines added by mistake after the closing tag.
Each slot PHP script may refer to a Smarty template instance for the slot as $_obweb->smslot, to the block as $_obweb->smblock, to the frame as $_obweb->smframe. Smarty is extensively documented on smarty.php.net.
![]() | The following information will be outdated soon |
|---|---|
In Obliquid CVS a new page to create a new local module has been added | |
To create a new module as a local module add a row to the module table: module(id_module, name, description, version, moddate, author, authoremail, authorsite, supportemail, copyright, license, ord, enable)
As you can see module has many fields but you can just insert id_module, name and enable for a test.
INSERT INTO sl_module (id_module, name, is_common, enable)
VALUES (1001, 'test', 'N', 'Y')
![]() | Choose an Id over 1000 |
|---|---|
You have to choose an Id over 1000, because every upgrade could delete and re-insert common modules, with lower Ids. | |
It is strongly advised that the module name contains only lowercase a-z letters plus the underscore. Pages for the modules will be stored in local/pages/test directory and templates in local/templates/test directory.
When customizing it may be necessary to store additional information in an existing table. You could just add columns to that table and use them in your scripts, and that would be enough, but you won't be able to use those columns through db_form class. Further, some tables, like the person table have a special configuration in the administration, and the new columns won't appear.
I explain the process of adding a column through an example: I want to add a column "eyes" to the person table to store the color of the eyes of a person.
I add the column to the person table.
ALTER TABLE sl_person ADD eyes VARCHAR(32) NOT NULL;
I then add the column description to the tabledesc table. The column type is one of the supported Metabase column types.
INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (100001, 'person', 'eyes', 'text', 32, 'N');
The third and last step is to add rows in slotfield table. This is needed only for the person table at the moment, and can be done through the slot administration.
![]() | Choose a high Id for local records |
|---|---|
You have to choose a high Id, because every upgrade will delete and re-insert tabledesc and slotfields rows, with lower Ids, but will preserve those with higher ones. Even Reset table with default data will preserve local data following this rule, even if reloading a table, provided that an Id over 100.000 is used. | |
Table of Contents
Obliquid has a very flexible permission (security) system. A security object can be assigned to any number of users or a groups (or combination). It is recommended that only groups be used in order to simplify the administration of the system. Currently there are four types of security objects defined. These are mainly for convenience and formatting. Once an object is defined, it can be used anywhere. The four types are:
![]() | Performance consideration |
|---|---|
The system keeps the security information for a particular user in the $_SESSION array, so checking for permission is a relatively inexpensive operation. | |
In addition to the real groups, there are also for special groups
Basic authorization is built into the system, and is used for navigation and slots security objects.
The icons displayed by core/nav are the entry points into the major functional groups areas in the system. Authorization to these entry pages is automatically checked by core/nav, so the user only sees those entry points that they are authorized to. In a similar way, the slots module/index, displays only pages that the user is authorized to see.
In addition, authorization to each slot is determined as the slot is loaded. So, even if a user were to type in the page name into the URL, they would not be shown any of the slots that they were not authorized to.
The system does not do any further security authorization automatically. There are two ways to address this. One is to insert appropiate calls to the security check function ($_obweb->has($a, $b, $c)). This is generally the way that access to specific records within a database would be handled. See the NEWS modules and how they handle restricted categories for an example. The second method would be to create a separate function, and use that as a parameter in the SLOT definition. So, you could created functions news_show_all() and news_show_unrestricted(). Depending on which function was called, you could determine what to show.
For example, language configuration can be used by anybody who has modlang operation for module core. An user will have modlang operation if he belongs to a group that has this operation. At present there is no code written to assign a security object directly to a user. You would need to manually update the database table.
![]() | Never check for users or groups |
|---|---|
It's not a good idea to grant permissions checking for a specific user or group id, but you have to check if he has a given operation. Add a new one only if an appropriate operation doesn't exist. | |
To check if a user has access to a security object, you need to use the has($a, $b, $c) function in Obliquidweb.
function slot_test_() {
global $_obweb;
//checks the modlang operation for the core module
if (!$_obweb->has(1, "modlang","")) {
/* no permission: take an appropriate action */
}
}
![]() | The appropriate action to take depends on the context |
|---|---|
It may be redirect to another page, hide the slot or remove a functionality (for example don't show a delete button). | |
has() method accepts three parameters. Notice that currently the third option is not used, but is included for future expansion, and is part of the call. What is placed in each depends on what type of security object is being tested.
Removing a functionality from a slot has often a dual impact: on html presentation and on php code. For example to remove a delete functionality, you've both to remove a delete button from html and not allow to execute the delete code section. It's very important to also not allow code execution because an expert user may post a forged form and delete what he/she's not allowed to delete.
Example PHP script:
<?php
function core_test_()
{
global $_obweb;
$user =& new user();
/* showing delete language button depends on having
* dellang operation (just an example, not a real operation)
*/
$show["dellang"]=$user->has(1, "dellang");
/* checking for dellang button push AND if it's allowed to push it */
if ($_GET["action"]=="dellang" AND $show["dellang"]) {
/* delete language code */
}
/* pass show array to Smarty slot template, so we can hide delete
* button if needed
*/
$_obweb->smslot->assign(array("show" => $show));
}
?>
Example HTML Smarty template:
{{if $show.dellang}}
<a href="index.php?page=core_test&action=delete">delete</a>
{{/if}}
Table of Contents
All urls defined into Obliquid must be relative. To improve further the quality and usability of single slots they can use the url class. This class is described in code documentation.
$url =& new url();
$url->addVal("action", "modlang");
echo $url->Build();
$url->Clear();
$url->dropVals(array("action", "langpos"));
$url->reload();
Internationalization is done with a GNU gettext approach, but without requiring PHP gettext extension. This approach is more comfortable than others for many reasons, but it is advised to keep messages as coherent as possible and to reuse _exactly_ the same message where appropriate. As nobody could have such strong memory there is a search function in the language support area where a programmer could look for reusable messages.
All the programmer should know is that every message to be internationalized in the core Obliquid should be in English and has to be passed to _l() function. On the other hand any internationalization occouring in local directory could be done with any language of choice as a base language. In any case, no message should be written directly into the template but always passed through templates variables from PHP script.
Translators will have to translate a text file in PO gettext format, like the one in this example: Italian common PO file found in common/locale/it_IT/obliquid_utf-8.po. The file has to be saved in UTF-8 format and it can be done with a text editor, by changing only the msgstr part of the file. There are also good tools that make the tranlation work easier, expecially when some of the messages were modified and a second translation has to occour. In this case all the message translations that didn't change won't be lost, but messages, even slightly changed needs to be fixed. Gettext tools make an attempt to find a similar message and suggest the translation in those cases, the message will be marked as fuzzy, that means that a human translator have to review and fix it.
Example PHP script
//defines a few messages
$msg["alert"]=_l("Pay attention please");
$msg["other"]=_l("Just another message");
//passes them to the slot template
$_obweb->smslot->assign("msg", $msg);
Example Smarty template
<span class="titlebig">{{$msg.alert}}</span><br>
<span class="textstandard">{{$msg.other}}</span>
A free text editor that supports UTF-8 encoding is SciTE. This editor works both on Linux/Unix and on Windows Operative systems. I personally use KBabel that is a specialized tool for PO files, working only on Linux afaik. poedit works on both Windows and Linux and should do the job with PO files, but I didn't try it yet.
Every slot inside a block of type title or title_em may have a help icon, normally not shown. To add it you have to call $_obweb method addButtons(), as in the example. By clicking on this help icon, a popup help window will be displayed.
$_obweb->addButtons(array("help"));This method has to be called inside slot code. For example if we want to add help to common/pages/core/conflang.php we have to call addButtons(). Obliquid will add the help icon for you and when somebody clicks on it, an help window will be shown. This window will be rendered by displaying common/core/templates/conflang_hlp.tpl and common/core/pages/conflang_hlp.php.
If the help button is called from php script in the local directory then the help window will be rendered by displaying local/core/templates/conflang_hlp.tpl and local/core/pages/conflang_hlp.php.
![]() | Displaying more than a button at once |
|---|---|
We can call addButtons with a list of button types: $_obweb->addButtons(array("print", "help")); | |
It's possibile to add a print icon to any slot: by clicking on the print icon the slot will be opened on its own in a new window, ready to be printed without any other slot. The new window will contain an additional GET parameter print=1 so the slot may adjust itself for print.
$_obweb->addButtons(array("print"));
It's also possible to add popup windows to show the PHP source code and the Smarty template for a slot.
$_obweb->addButtons(array("source", "template"));
It's also possible to hide a slot (for example when an user is not authorized to see a content or a functionality). To do this is enough to set $_obweb->showslot=false in the slot PHP script. It is strongly advised to return from the slot function after this otherwise the rest of the script would be executed anyway.
<?php
function core_test_()
{
global $_obweb;
if (some condition) {
$_obweb->showslot=false;
return;
}
}
?>
You may need to redirect an user to a different page when he/she's not allowed to see the whole page, or after a form submission, to avoid browsers asking to resend form data when hitting the back button.
To do this, you've to call PHP header function, followed by exit(). Adding exit() is very important otherwise code after header() will be still executed.
header("Location: index.php?page=home");
exit();
To display an error message as a javascript alert, call the function addErr(). If addErr() is called more than one time in the same page messages are appended, so it's advisable to end every message with a newline (\n).
$_obweb->addErr("Error message\n");
Error messages get automatically cleaned after display, but they are still remembered even after redirecting to another page. Even after redirecting in page mypage, our error message is still shown.
$_obweb->addErr("You did a 'bad' thing\n");
header("Location: index.php?page=mypage");
exit();
To display a popup confirmation request as a javascript confirm, call the function confirm(). Calling the function will popup a javascript dialog box with OK and Cancel buttons. Pressing OK the browser will be redirected to a page with the same url of the previous page with 'confirm' GET parameter set to Y. Pressing Cancel 'confirm' GET parameter will be set to N.
Here is an example showing how the function can be used. The confirmation, in this example, is shown when a delobj GET parameter is found.
if ($_GET["delobj"]) { //first time here: ask for confirm
$_obweb->confirm(_l("Are you sure?"));
}
if ($_GET["delobj"] AND $_GET["confirm"]=="Y") {
//second time and user confirmed: do your actions
}
if ($_GET["delobj"] AND $_GET["confirm"]) {
//after second time user confirmed or refused
$url =& new url(); //creates an url object
$url->dropVals(array("confirm", "delobj")); //removes params from url
$url->reload(); //reloads the page
}
You can execute arbitrary Javascript code when you move to a new page or open a popup. Since HTML body tag is in the theme frame.tpl, you have to pass to onload Smarty variable an appropriate Javascript command or commands, with rows terminated by a semicolon.
$_obweb->smframe->assign("onload", "alert('test');");
![]() | Generic onload XHTML syntax |
|---|---|
The simplest way of calling a simple Javascript command is calling it directly in the onload tag.
<body onload="alert('hihi!')">
You can also call multiple commands separated by a semicolon.
<body onload="alert('hihi!');alert('how are you?')">
If your script is not just a simple command, it's better to call a separate function. <body onload="myfunction()">
| |
Use the javascript popup() function, defined by Obliquid framework inside html page frame of each theme.
<a href="#" onclick="popup('index.php?page=home')">open</a>
It's also possible to change the default size of the popup.
<a href="#" onclick="popup('index.php?page=home','width=200,height=100')">open</a>
If a site has less than a hundred users, it's viable to use a simple drop down menu to choose a person, but if a site has thousands of users, then it's not a good idea.
The solution for this problem is to have a javascript popup allowing to search a user that pass the search result to our main form. This is already implemented in Obliquid.
To add it to a form inside a slot, you have first to copy and paste the following javascript function at the beginning of your slot template.
<script language="JavaScript">
function OpenChoosePerson(value) {
p="toolbar=no,location=no,directories=no,status=no,menubar=no,width=700,height=400"
+",resizable=yes,scrollbars=yes";
URLtoOpen="index.php?page=user_choose&value="+value;
window.open(URLtoOpen,"choose",p);
return false;
}
</script>
Then you've to make sure that your form is named "pform". This is very important because the form will be referenced by name from the popup.
<form method="post" NAME="pform">
The next step is to add the following piece of html inside the slot template, where you want to make appear the control to choose a person.
<a href="" onClick="javascript: return OpenChoosePerson(1);"
class="textstandard"><span class="textstandard">{{$msg.select}} »</span></a>
<input type="text" size="35" name="person1" value='{{$frm.person1}}'
class="textform" disabled>
<input type="text" size="5" name="id_person1" value='{{$frm.id_person1}}'
class="textform">
This is enough to do the trick. Note that i used frm.person1 and frm.id_person1 Smarty variables to pass values to the form when in modify mode, but you should feel free to choose your own names. Remeber to close the form.
</form>
Obliquid allows multiple sites to share a single database with the trick of table prefix. Setting up two sites in the same database, but with a different table prefix will make them two separate sites without any shared data. This concept is widespread and supported by many other applications.
Sometimes it's needed to run multiple sites with a single database, instead. For example we want to address different users and we need to have a different content and a different graphic style, but we want a single user base and a single administration. Users from different sites will normally belong to different groups, and in this way we can identify them.
The table configparms contains site-specific information like the site title or the site logo. To solve this problem I added an optional table suffix that will apply to configparms table only.
To use it, just two steps are needed. First change or add the following line to local/configs/base.php, second copy table configparms to a name with both prefix and suffix. Repeat these steps for all the sites that have to share the same database, and you are done.
/additional suffix for configparms table. default "" $_obweb->tsuffix="_we";
Table of Contents
There are two levels of navigation within Obliquid.
One is the typical icon navigation bar across the top. These icons typically represent the main entry points within the various modules in Obliquid. So, there are a "view posts", and an "administer posts" icons. All the icons are defined in an XML file common/navxml/nav.xml. Which icons actually are displayed to the current user depends on their permissions. The function 'getNav' in common/classes/obliquid/nav.php automatically checks permissions, and only returns those icons which the current user is allowed access to.
The second type of navigation is typically a set of text links that is on the left of the screen. These are normally used for navigation within a module, and are displayed by common/pages/mmmm/index.php. The contents of these links are also controlled in XML files in common/navxml/. The files are named mmmm.xml, where mmmm is the module name. Not all modules have an index.php and a corresponding text link navigation because there is typically only one entry point, and all the rest of the navigation is via pick lists from the main screen.
As mentioned in the introduction, the icons and text are controlled by XML navigation files contained in common/navxml/ and local/navxml/. These all have the same definition. The items in local/navxml/ override those in common/navxml. But, it is not necessary to copy all the parameters from common/navxml to local/navxml. Only those parameters in a particular NAV item need to be specified in local/navxml.
Here is a simple NAV.XML file which will serve as an example.
<?xml version="1.0" encoding="UTF-8"?>
<NAVOBJECTS>
<NAV PAGE="home" ORD="10">
<THEME NAME="*default*">
<TEXT>Home</TEXT>
<IMAGE>common/images/core/home.gif</IMAGE>
</THEME>
</NAV>
<NAV PAGE="user_usermymod" ORD="140">
<THEME NAME="*default*">
<TEXT>My profile</TEXT>
<IMAGE>common/images/user/profile.png</IMAGE>
<PARMS>"&id_person=".$_SESSION['_obperson']['id_person'];</PARMS>
</THEME>
</NAV>
<NAV LINK="http://dev.obliquid.com" ORD="55">
<THEME NAME="*default*">
<TEXT>Obliquid Development Site</TEXT>
</THEME>
</NAV>
</NAVOBJECTS>
NAV has three attributes.
THEME has one attribute.
THEME has three elements.
In order to override any of the attributes or entries, all you need to do is specify them in a file in local/navxml/ with the same name as the one that contains what you want to override (nav.xml, posts.xml, and such).
The overrides are processed in the following order.
Actually creating a navigation script is a simple process. All the hard work is in creating the XML file. The function getNav("module") in common/classes/obliquid/nav.php returns an index array. Each entry in the array with three values. The array is in order by ORD.
Here is what core/index.php looks like.
require_once "common/classes/obliquid/nav.php";
/** access structure for core module */
function core_index_()
{
global $_obweb;
$nav = & new nav();
$corelinks = $nav->getNav("core"); //Get the array for the icons
//Now assign them for the template, and we are done
$_obweb->smslot->assign("corelinks", $corelinks);
}
And here is what index.tpl looks like.
{{* $Id: navigation.xml,v 1.6 2003/11/30 19:44:48 slocati Exp $ *}}
<table width="160">
{{foreach from=$corelinks item=alink}}
<tr><td>
{{if $alink[2] eq "*none*"}}
<a href="{{$alink[0]}}" class="textmini">{{$alink[1]}}</a>
{{else}}
<a href="{{$alink[0]}}" class="textmini">
<img src="{{$alink[2]}}" width="16" height="16" border="0"> {{$alink[1]}}</a>
{{/if}}
</td></tr>
{{/foreach}}
</table>
Free software is a collaborative effort that brings better software. You may decide to join Obliquid team because you like programming, or to improve your programming skills with the help of other members. For an IT professional joining the team may be convenient to be able to influence future directions of Obliquid, to have the code tested by a broad user base, to receive help from others.
Table of Contents
To be involved in the project the suggested way is to go to the forum, read a bit of the latest discussion and then introduce yourself and tell us what would you like to do, or simply offer help for things left behind.
Besides this we are maintaining a todo list in the 'Tasks' link at the top of this sourceforge forum. Once a person is part of the team he/she can take any of the unassigned tasks. Before doing that, expecially the first time, it is required to tell others about this on the forum.
What are we looking for:
Register yourself on sourceforge, the site providing tools and bandwith for open source projects, and tell us your username. CVS is the Versioning System that allows remote collaboration. If you need to edit directly source code or the manual, then you need CVS write access.
“ CVS (Concurrent Versions System) is a tool used by many software developers to manage changes within their source code tree. CVS provides the means to store not only the current version of a piece of source code, but a record of all changes (and who made those changes) that have occurred to that source code. Use of CVS is particularly common on projects with multiple developers, since CVS ensures changes made by one developer are not accidentally removed when another developer posts their changes to the source tree. ” -- from sourceforge help.
Fetching obliquid source code export CVS_RSH=ssh cvs -z3 -d:ext:developername@cvs.sourceforge.net:/cvsroot/obliquid co obliquid
Fetching the manual export CVS_RSH=ssh cvs -z3 -d:ext:developername@cvs.sourceforge.net:/cvsroot/obliquid co manual
A great effort was spent to write Obliquid in a tidy and organized way, so try to keep things tidy by following this coding standards, and by using common sense.
(setq c-basic-indent 4)
(setq tab-width 4)
(setq indent-tabs-mode nil)
In vim write the following into your .vimrc:
set shiftwidth=4
set expandtab
set tabstop=4
:set ff=unix
:w
To convert from unix to dos file format use :set ff=dos instead.
Classes should be given descriptive names. Avoid using abbreviations where possible. Class names should always begin with an uppercase letter, further words inside the class name should be capitalized also. Use English language. Examples: NewsItem, Group.
Functions and methods should begin with a lower case letter and should be given descriptive names. Avoid using abbreviations where possible. Use English language. Examples: getNews(), saveGroup(). Private method shold start with an underscore. Example: _tidy()
Db table names should be singular, all lower case and so should be field names. Primary/Unique key identifier should be "id_" + tablename. Words separated by an underscore. The most significative name first. Example date_start and not start_date.
A common module is a module integrated into Obliquid, it will be stored inside the common directory tree. The common directory tree will be overwritten by upgrades, so it's not advised to store anything there before agreeing with us.
It will be now explained the steps necessary to create a news module. First it will be necessary to add a row to the module table, but it can't be simply added to the database, because this row will have to be created by the next setup, and has to work for every possible table prefix. This is done by adding a row to common/configs/module.tpl file. In our case:
INSERT INTO {{$tprefix}}module VALUES (4, 'news',
'Simple content management for publishing purposes', '0.1', '2003-01-04',
'Stefano Locati', 'stefano@obliquid.it', 'www.obliquid.com', 'info@obliquid.it',
'Copyright (c) 2003 Obliquid', 'LGPL', 'common/docs/license.txt', 4, 'Y')This insert is here broken on several rows for convenience, but it has to be on a single line in module.tpl file, or the insert will fail. To activate the change, we have to go to a core module page, like "Page groups, pages, slots", and choose "Resets a table to default" in the left menu, select module and press ok. This operation will reload the module table. A new setup will do it too.
A module will also need php scripts and html templates, our news module php scripts will be in common/pages/news directory and our templates will be in common/templates/news directory. This two news directory has thus to be created, notice that this name is the same of the module. This is a mandatory rule.
A module will need an access point, generally this is done through core/nav slot. This is normally shown as a top icon bar, we will then need to find an appropriate icon that will be stored in common/images/news directory that we have to create for the purpose. We will store there a news.gif icon, of size 32x32 pixels.
We can now open common/pages/core/nav.php to add the new icon and text to the $navpages array.
$navpages["news_adm"] = array(_l("News Administration"),"common/images/news/news.gif");
Note that we need to call _l() to translate the popup text into the correct language.
We have then to decide when this news icon will be shown, and it will be to users that have the news_adm page. Since this security object still doesn't exist the icon won't be shown yet.
Therefore we open common/configs/security.tpl and add a row for the new news_adm page. We can just pick the next available ID number for this row. It will be a objtype='n' (Navigation Page). Be careful to make sure that you have the ':' in the right places. The demo site has three groups defined. g1 is Administrators g2 is Developers, and g3 is Customers. Since we want to permit both the Administrators and Developers to administer news, we need to add both to the security table.
INSERT INTO {{$tprefix}}security VALUES (14,':news_adm:','g1','n')
INSERT INTO {{$tprefix}}security VALUES (15,':news_adm:','g2','n')
Now we need this new security to really appear to continue our work. This can be done as we did before to reload the module table, but this time we need to reload the security table. Of course a new setup will reload this new values too.
We could do this also by logging on as pascal and going through the Security and Groups icon. But that would only change the database, and the next time the database got reloaded our changes would be gone.
Now, despite all this, clicking on the new icon will give an error, because we didn't create any news_adm page yet. This can be done by editing manually local/configs/config.xml or by using site configuration. We use the second way: click on Page groups, pages, slot icon and choose add a new page. Insert news_adm as name and news as group and don't modify the other two fields, then click on the ok icon: the new page is now created (empty).
To add core/nav slot in this page we go down to "Creates a new slot in page news_adm" window and type core/nav as name, center1 for position and none for block, leaving the other fields unchanged, then we can click on the ok icon. We can already test our page by clicking on it. It will have only the icon bar.
For example we can now add a core/changelang slot to the left by typing core/changelang for name, left2 for position, title for block and clicking ok. We also have to add the most important slot for this page: news/adm. We have to type news/adm for name, center2 for position and click ok. If we test the news_adm page now it will show two errors: this is because there is still no php script and no template file.
We start by creating a adm.php file inside common/pages/news directory, including the disclaimer too.
<?php
/* Obliquid - PHP/XML application framework for groupware websites.
* Copyright (C) 2003 Stefano Locati <info@obliquid.it>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*/
/** News administration
* @version $Id: common_mod.xml,v 1.5 2004/02/11 00:38:31 vrtisworks Exp $
* @package news
*/
function news_adm_()
{
global $_obweb;
$_obweb->smblock->assign("title", _l("News Administration"));
}
?>
Then we create a template file called adm.tpl inside common/templates/news directory.
Now when we click on the icon, we still do not see anything. That is because we did not create any security access to the news/adm slot. Remember that there might be some slots on this page that everybody can see (such as core/nav), but not everybody should be allowed to get to news/adm. So we need to go back to security.tpl and add the two entries for news/adm.
INSERT INTO {{$tprefix}}security VALUES (31,'news/adm::','g1','s')
INSERT INTO {{$tprefix}}security VALUES (32,'news/adm::','g2','s')
Notice that these entries are type 's' (Slots). Now after we reload the security table, as explained before, we can click on the icon and see our work!
A common and useful slot that is normally present in every page of a module is the module index that allows navigation within the module. This slot is usually called index.php. For example for the core module it will be stored in common/pages/core/index.php, common/templates/core/index.tpl and common/navxml/core.xml
Here is what core/index.php looks like.
require_once "common/classes/obliquid/nav.php";
/** access structure for core module */
function core_index_()
{
global $_obweb;
$nav = & new nav();
$corelinks = $nav->getNav("core"); //Get the array for the icons
//Now assign them for the template, and we are done
$_obweb->smslot->assign("corelinks", $corelinks);
}
And here is what index.tpl looks like.
{{* $Id: common_mod.xml,v 1.5 2004/02/11 00:38:31 vrtisworks Exp $ *}}
<table width="160">
{{foreach from=$corelinks item=alink}}
<tr><td>
{{if $alink[2] eq "*none*"}}
<a href="{{$alink[0]}}" class="textmini">{{$alink[1]}}</a>
{{else}}
<a href="{{$alink[0]}}" class="textmini">
<img src="{{$alink[2]}}" width="16" height="16" border="0"> {{$alink[1]}}</a>
{{/if}}
</td></tr>
{{/foreach}}
</table>
And finally, here is what core.xml looks like. For details about the format and information in a navxml file, please see the section on "Site Naviation".
<?xml version="1.0" encoding="UTF-8"?>
<!-- $Id: common_mod.xml,v 1.5 2004/02/11 00:38:31 vrtisworks Exp $ -->
<NAVOBJECTS>
<NAV PAGE="core_confpagegroup" ORD="10">
<THEME NAME="*default*">
<TEXT>List modules and their pages</TEXT>
</THEME>
</NAV>
<NAV PAGE="core_configparms" ORD="20">
<THEME NAME="*default*">
<TEXT>Configure parameters</TEXT>
</THEME>
</NAV>
<NAV PAGE="core_cron" ORD="25">
<THEME NAME="*default*">
<TEXT>Scheduled jobs</TEXT>
</THEME>
</NAV>
<NAV PAGE="core_admtheme" ORD="30">
<THEME NAME="*default*">
<TEXT>Manage themes</TEXT>
</THEME>
</NAV>
<NAV PAGE="core_conflang" ORD="40">
<THEME NAME="*default*">
<TEXT>Configure languages</TEXT>
</THEME>
</NAV>
<NAV PAGE="core_resethas" ORD="45">
<THEME NAME="*default*">
<TEXT>Reload your security</TEXT>
</THEME>
</NAV>
<NAV PAGE="core_demodata" ORD="50">
<THEME NAME="*default*">
<TEXT>Load demo data</TEXT>
</THEME>
</NAV>
</NAVOBJECTS>
To make this slot appear we will need to insert the permission to see the slot in the security table.
INSERT INTO {{$tprefix}}security VALUES (141,'core/index::','g1','s')
INSERT INTO {{$tprefix}}security VALUES (142,'core/index::','g2','s')
Further, we will need a navigation permission for every link in this slot. In this way we are able to deliver a different set of links for each group.
INSERT INTO {{$tprefix}}security VALUES (143,':core_mypage:','g2','n')
The calendar supports multiple types of events: meetings, work sessions, accounting, calls and recalls and availabilities.
Availabilities can be inserted as repeated events: for example every monday from 10 to 12am. Until Obliquid 0.5.0 only the generation rule was saved into database and the derived events were computed at each page reload. Unfortunately this approach, even if works it gets easily too slow.
In new versions of Obliquid, generated events are saved in database. To distinguish the inserted events from the generated ones, the field id_categ of cal table is used. When id_categ = 0, then our availability event is an inserted event, when id_categ > 0 then it's a generated one and the value of id_categ is the id_cal of the original event.
Table of Contents
A cookbook to remind how to do common operations.
Some short notes for developers: how to build a release. Execute these steps carefully and in the suggested order.
Phase 1: Keeping the house clean
Phase 2: build the package
export CVS_RSH=ssh cvs -z3 -d:ext:slocati@cvs.sourceforge.net:/cvsroot/obliquid co obliquid
This library is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
Table of Contents
Table of Contents
“DocBook provides a system for writing structured documents using SGML or XML. It is particularly well-suited to books and papers about computer hardware and software, though it is by no means limited to them. (From Docbook, The definitive guide) ”
For learning how to write documentation using docbook, I found this tutorial. I just read a chapter of it, but it seems fine as an introduction. For details you can always search The definitive guide. Writing Documentation Using DocBook -- A Crash Course
The complete docbook specification is quite large, but not all is necessary for writing this manual. I keep a list of used markup here. If it's in this list it can be used, if it is not in this list, but it's necessary, it can be added. It has to be added in this list and configured in the style sheet too.
| abstract -- A summary |
| appendix -- An appendix in a Book or Article |
| author -- The name of an individual author |
| authorgroup -- Wrapper for author information when a document has multiple authors or collaborators |
| book -- A book |
| bookinfo -- Meta-information for a Book |
| caption -- A caption |
| classname -- The name of a class, in the object-oriented programming sense |
| chapter -- A chapter, as of a book |
| command -- The name of an executable program or other software command |
| guibutton -- The text on a button in a GUI |
| computeroutput -- Data, generally text, displayed or presented by a computer |
| copyright -- Copyright information about a document |
| emphasis -- Emphasized text |
| example -- A formal example, with a title |
| filename -- The name of a file |
| function -- The name of a function or subroutine, as in a programming language |
| guilabel -- The text of a label in a GUI |
| imagedata -- Pointer to external image data |
| imageobject -- A wrapper for image data and its associated meta-information |
| important -- An admonition set off from the text |
| itemizedlist -- A list in which each entry is marked with a bullet or other dingbat |
| listitem -- A wrapper for the elements of a list item |
| literal -- Inline text that is some literal value |
| literallayout -- A block of text in which line breaks and white space are to be reproduced faithfully |
| markup -- A string of formatting markup in text that is to be represented literally |
| mediaobject -- A displayed media object (video, audio, image, etc.) |
| member -- An element of a simple list |
| methodname -- The name of a method |
| note -- A message set off from the text |
| orderedlist -- A list in which each entry is marked with a sequentially incremented label |
| para -- A paragraph |
| part -- A division in a book |
| partinfo -- Meta-information for a Part |
| partintro -- An introduction to the contents of a part |
| programlisting -- A literal listing of all or part of a program |
| quote -- An inline quotation |
| screenshot -- A representation of what the user sees or might see on a computer screen |
| title -- The text of the title of a section of a document or of a formal block-level element |
| ulink -- A link that addresses its target by means of a URL (Uniform Resource Locator) |
| userinput -- Data entered by the user |
| varname -- The name of a variable |
| warning -- An admonition set off from the text |
| year -- The year of publication of a document |
| para -- A paragraph |
Table of Contents
One of the goals of Obliquid project is to allow customizability of your site or application, while making the upgrade to the next version easy. This is a hard problem. We are trying our best to reach this goal, but we didn't reach it yet. One step forward in this direction is the new pagexml layout that has a little xml file for each page instead of a big one, that allows you to redefine pages. This new layout was introduced in Obliquid 0.6.0.
We are trying to release upgrade packages that will help users to upgrade. They were introduced early on, but they were discontinued then, because making upgrade packages was stealing too much time from development. Starting from Obliquid 0.5.0, we are reaching a more mature status, so we try to always release those upgrade packages.
The upgrade process is only in part automatic. It will require human support to do some of the operations. It could also be done manually, if you want the greatest control. We also have the need to have a documentation of changes between versions, so I thought to write it as an appendix in our manual.
Overwrite all the common files with the new ones. You can do it with ftp, with a file manager or with the shell cp -r obliquid-0.9.4/common/ obliquid-0.9.3/
Execute the following queries -- If your prefix is not sl_,
INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2720, 'log', 'id_log', 'integer', 0, 'Y'); INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2721, 'log', 'id_change', 'integer', 0, 'N'); INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2722, 'log', 'id_person', 'integer', 0, 'N'); INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2723, 'log', 'logtime', 'timestamp', 0, 'N'); INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2724, 'log', 'operation', 'text', 8, 'N'); INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2725, 'log', 'level', 'integer', 0, 'N'); INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2726, 'log', 'tablen', 'text', 64, 'N'); INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2727, 'log', 'prikey', 'text', 128, 'N'); INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2729, 'log', 'newvalue', 'text', 0, 'N'); INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2730, 'log', 'oldvalue', 'text', 0, 'N'); INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2731, 'log', 'description', 'text', 255, 'N'); CREATE TABLE sl_log ( id_log int(11) NOT NULL default '0', id_change int(11) NOT NULL default '0', id_person int(11) NOT NULL default '0', logtime datetime default NULL, operation varchar(8) NOT NULL default '0', level int(11) NOT NULL default '1', tablen varchar(64) NOT NULL default '', prikey varchar(128) NOT NULL default '', newvalue text NOT NULL, oldvalue text NOT NULL, description text NOT NULL, UNIQUE KEY id_log (id_log) ) TYPE=MyISAM; CREATE TABLE _sequence_sl_log ( sequence int(11) NOT NULL auto_increment, PRIMARY KEY (sequence) ) TYPE=MyISAM AUTO_INCREMENT=1 ; CREATE TABLE _sequence_sl_log2 ( sequence int(11) NOT NULL auto_increment, PRIMARY KEY (sequence) ) TYPE=MyISAM AUTO_INCREMENT=1 ;
Overwrite all the common files with the new ones. You can do it with ftp, with a file manager or with the shell cp -r obliquid-0.9.2/common/ obliquid-0.9.1/
Overwrite all the common files with the new ones. You can do it with ftp, with a file manager or with the shell cp -r obliquid-0.9.2/common/ obliquid-0.9.1/
Copy common/scripts/index.php over the main index.php, copy favicon.ico too if you want.
Execute the following queries -- If your prefix is not sl_, adjust accordingly
ALTER TABLE sl_person CHANGE provincia provincia VARCHAR(32) DEFAULT NULL;
INSERT INTO sl_country (name, code) VALUES ('Guyana', 'GY');
INSERT INTO sl_slot (id_slot, id_module, slot, comment) VALUES (225,'3','addnote','Add or modify a Note entry');
UPDATE sl_slotfield SET enable = 'Y' WHERE id_slotfield = 10;
UPDATE sl_slotfield SET enable = 'Y' WHERE id_slotfield = 61;
UPDATE sl_slotfield SET intype = 'TITLE' WHERE id_slotfield = 56;
UPDATE sl_slotfield SET intype = 'TITLE' WHERE id_slotfield = 64;
UPDATE sl_slotfield SET intype = 'TITLE' WHERE id_slotfield = 69;
UPDATE sl_slotfield SET intype = 'PASSWORD' WHERE id_slotfield = 71;
UPDATE sl_slotfield SET intype = 'TITLE' WHERE id_slotfield = 107;
UPDATE sl_slotfield SET enable = 'Y' WHERE id_slotfield = 112;
UPDATE sl_slotfield SET intype = 'TITLE' WHERE id_slotfield = 115;
UPDATE sl_slotfield SET intype = 'TITLE' WHERE id_slotfield = 120;
UPDATE sl_slotfield SET intype = 'TITLE' WHERE id_slotfield = 157;
UPDATE sl_slotfield SET enable = 'Y' WHERE id_slotfield = 162;
UPDATE sl_slotfield SET intype = 'TITLE' WHERE id_slotfield = 165;
UPDATE sl_slotfield SET intype = 'TITLE' WHERE id_slotfield = 170;
UPDATE sl_slotfield SET intype = 'PASSWORD' WHERE id_slotfield = 172;
UPDATE sl_slotfield SET enable = 'Y' WHERE id_slotfield = 211;
UPDATE sl_slotfield SET enable = 'Y' WHERE id_slotfield = 257;
DELETE FROM sl_slotfield WHERE id_slotfield = 258;
UPDATE sl_slotfield SET enable = 'Y' WHERE id_slotfield = 356;
UPDATE sl_slotfield SET enable = 'Y' WHERE id_slotfield = 412;
UPDATE sl_slotfield SET enable = 'Y' WHERE id_slotfield = 606;
UPDATE sl_slotfield SET intype = 'TITLE' WHERE id_slotfield = 706;
UPDATE sl_slotfield SET intype = 'TITLE' WHERE id_slotfield = 714;
UPDATE sl_slotfield SET intype = 'TITLE' WHERE id_slotfield = 719;
UPDATE sl_slotfield SET intype = 'TITLE' WHERE id_slotfield = 726;
UPDATE sl_tabledesc SET length = 32 WHERE id_tabledesc = 318;
Go to developers' tools, select 'Reset table with default data' from the left side menu and choose msg_text table and 'Empty and reload table completely', press OK. If you've customized your email messages, the changed message is doc_appr, both in English and Italian. Beware that also now you enable or disable a message, not a message/language combination as it was happening before. The language sent will depend on the language of the sender (if there is interest, it could be in the language of who receives).
Bid Chief, Bid quality and Statistics roles has been modified, reload them. The change is the addition of the slots prj/phasehours and prj/hourconf
Lastly, go to developers' tools, choose 'Load PO translation files' on the left menu and press OK to reload traslations
First of all overwrite all common files with the new ones. For example with unix shell cp -r obliquid-0.9.1/common/ obliquid-0.9.0/, or you can overwrite the common dir using ftp
Execute the following queries -- If your prefix is not sl_, adjust accordingly
CREATE TABLE _sequence_sl_tabledesc (
sequence int(11) NOT NULL auto_increment,
PRIMARY KEY (sequence)
) TYPE=MyISAM AUTO_INCREMENT=100001;
INSERT INTO _sequence_sl_tabledesc VALUES (100000);
ALTER TABLE sl_doc_cat1 ADD id_parent INT NOT NULL;
CREATE TABLE _sequence_sl_doc_cat1_parent (
sequence int(11) NOT NULL auto_increment,
PRIMARY KEY (sequence)
) TYPE=MyISAM AUTO_INCREMENT=1;
CREATE TABLE sl_doc_cat1_parent (
id_doc_cat1_parent int(11) NOT NULL default '0',
name char(80) NOT NULL default '',
UNIQUE KEY doc_cat1 (id_doc_cat1_parent)
) TYPE=MyISAM;
INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2705, 'doc_cat1', 'id_parent', 'integer', 0, 'N');
INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2706, 'doc_cat1_parent', 'id_doc_cat1_parent', 'integer', 0, 'Y');
INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2707, 'doc_cat1_parent', 'name', 'text', 80, 'N');
INSERT INTO sl_configparms (name, setting, description, id_module, ord) VALUES ('cat1_parent', 'N', 'Use category 1 with parent (doublecombo)', 5, 50);
INSERT INTO sl_configparms (name, setting, description, id_module, ord) VALUES ('signup_enable', 'Y', 'Allow guests to create a new user record.', 2, 15);
UPDATE sl_slotfield SET label = '#passwd' WHERE `d_slotfield = 422;
The new roles cal_view and cal_adm have been introduced. security_partial, security_full, doc_adm and site_conf have been modified.
First of all overwrite all common files with the new ones. For example with unix shell cp -r obliquid-0.9.0/common/ obliquid-0.8.1/ or you can overwrite the common dir using ftp
Execute the following queries
INSERT INTO sl_configparms (name, setting, description, id_module, ord) VALUES ('cat3_group', '0', 'Id group to connect to category 3, 0 to use a custom category 3', 5, 40);
INSERT INTO sl_configparms (name, setting, description, id_module, ord) VALUES ('err_handling', 'none', 'Error handling one of (none, email, popup) Popup will be shown only if the user can see core/confpagegroup slot', 8, 5);
INSERT INTO sl_msg_text VALUES (84, 9, 'prj_prepare_invoice', 'en', 'Prepare invoice', 'The following phases have been closed, and an invoice should be prepared:\r\n\r\n{{foreach from=$p.phase item=ph}}Phase description:{{$ph}}\r\n{{/foreach}}Organization: {{$p.organization}}\r\nWork type: {{$p.activity}}\r\nBid code: {{$p.reference}}\r\nReport: {{$p.link}}\r\n\r\nClosed by: {{$p.name}}', '$p[organization] - Organization name
$p[activity] - Work type
$p[reference] - Bid Code
$p[phase] - An array of Phase descriptions
$p[link] - Link to the report screen
$p[name] - Name of person who closed the phase.', NOW(), 'Y');
INSERT INTO sl_msg_text VALUES (85, 9, 'prj_prepare_invoice', 'it', 'Preparare fattura', 'Le seguenti fasi sono state chiuse e bisogna fatturare:\r\n\r\n{{foreach from=$p.phase item=ph}}Descrizione fase:{{$ph}}\r\n{{/foreach}}Organizzazione: {{$p.organization}}\r\nTipo di lavoro: {{$p.activity}}\r\nCodice offerta: {{$p.reference}}\r\nCollegamento al sito: {{$p.link}}\r\n\r\nChiusa da: {{$p.name}}', '$p[organization] - Organizzazione
$p[activity] - Tipo di lavoro
$p[reference] - Codice offerta
$p[phase] - Un array con le descrizioni delle fasi
$p[link] - Collegamento al sito
$p[name] - Nome della persona che ha chiuso la fase.', NOW(), 'Y');
INSERT INTO sl_page VALUES ('core_javaedit',1,'Y','Enhanced text file editor, sends a message to people subscribed to core_edit on save');
INSERT INTO sl_slot (id_slot, id_module, slot, comment) VALUES (44, '1', 'javaedit', 'Enhanced text file editor, sends a message to people subscribed to core_edit on save');
INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (202, 'news_object', 'pos', 'integer', 0, 'N');
INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (200, 'news_text', 'pos', 'integer', 0, 'Y');
INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (201, 'news_text', 'blocklayout', 'integer', 0, 'N');
INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2550, 'news_cat', 'topic_images', 'text', 1, 'N');
INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2600, 'news_layout', 'id_news_layout', 'integer', 0, 'Y');
INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2601, 'news_layout', 'name', 'text', 80, 'N');
INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2700, 'prj_assigned', 'id_phase', 'integer', 0, 'Y');
INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2701, 'prj_assigned', 'id_person', 'integer', 0, 'Y');
INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2702, 'prj_assigned', 'id_project', 'integer', 0, 'Y');
ALTER TABLE `sl_news_object` ADD `pos` INT NOT NULL ;
ALTER TABLE `sl_news_text` ADD `pos` INT NOT NULL ,
ADD `blocklayout` INT NOT NULL ;
ALTER TABLE `sl_news_text` DROP INDEX `news_text` ;
ALTER TABLE `sl_news_text` ADD UNIQUE ( `id_news_item` , `lang` , `pos`);
ALTER TABLE `sl_news_cat` ADD `topic_images` CHAR( 1 ) NOT NULL ;
CREATE TABLE `sl_news_layout` (
`id_news_layout` int(11) NOT NULL default '0',
`name` char(80) NOT NULL default ''
) TYPE=MyISAM;
INSERT INTO `sl_news_layout` VALUES (1, 'Text on the left, photos on the right');
INSERT INTO `sl_news_layout` VALUES (2, 'Photos on the left, text on the right');
INSERT INTO `sl_news_layout` VALUES (3, 'Photos on top');
INSERT INTO `sl_news_layout` VALUES (4, 'Photos tiled horizontally on the left, text on the right');
CREATE TABLE `sl_prj_assigned` (
`id_phase` int(11) NOT NULL default '0',
`id_person` int(11) NOT NULL default '0',
`id_project` int(11) NOT NULL default '0',
UNIQUE KEY `id_prj_assigned_idx` (`id_phase`,`id_person`)
) TYPE=MyISAM;
Your upgrade should be now complete except for slot security to view the new additions. I suggest you to load some roles and assign them to groups
First of all overwrite all common files with the new ones. For example with unix shell cp -r obliquid-0.8.1/common/ obliquid-0.8.0/ or you can overwrite the common dir using ftp
Execute the following queries
INSERT INTO sl_security (id_security, ifq, ug, objtype) VALUES (174, 'user/userview::', 'g2', 's'); INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2590, 'persparms', 'id_module', 'integer', 0, 'Y'); INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2591, 'persparms', 'name', 'text', 100, 'Y'); INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2592, 'persparms', 'ug', 'text', 12, 'Y'); INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2593, 'persparms', 'setting', 'text', 255, 'N'); INSERT INTO sl_tabledesc (id_tabledesc, tablename, field, type, length, is_primary) VALUES (2594, 'persparms', 'priority', 'integer', 0, 'N'); CREATE TABLE `sl_persparms` ( `id_module` int(11) NOT NULL default '0', `name` varchar(100) NOT NULL default '', `ug` varchar(12) NOT NULL default '', `setting` varchar(255) NOT NULL default '', `priority` int(11) NOT NULL default '0', PRIMARY KEY (`id_module`,`name`,`ug`) ) TYPE=MyISAM; ALTER TABLE `sl_group_group` CHANGE `id_son` `id_son` CHAR( 6 ) DEFAULT '0' NOT NULL; UPDATE sl_tabledesc SET type='text', length=6 WHERE tablename='group_group' AND field='id_son';
At this point add security to access to user_roleadd and its slot
![]() | Work in progress |
|---|---|
This section is a work in progress, it's not complete. It's here basically for me, don't use it until it's complete | |
1) Overwrite all the files in the common directory tree.
2) Add the following tables, changing the prefix if needed.
CREATE TABLE _sequence_sl_module ( sequence int(11) NOT NULL auto_increment, PRIMARY KEY (sequence) ) TYPE=MyISAM; CREATE TABLE _sequence_sl_posts_cat ( sequence int(11) NOT NULL auto_increment, PRIMARY KEY (sequence) ) TYPE=MyISAM; CREATE TABLE _sequence_sl_posts_item ( sequence int(11) NOT NULL auto_increment, PRIMARY KEY (sequence) ) TYPE=MyISAM; CREATE TABLE _sequence_sl_posts_object ( sequence int(11) NOT NULL auto_increment, PRIMARY KEY (sequence) ) TYPE=MyISAM; CREATE TABLE _sequence_sl_translate ( sequence int(11) NOT NULL auto_increment, PRIMARY KEY (sequence) ) TYPE=MyISAM; CREATE TABLE sl_country ( name char(50) NOT NULL default '', code char(2) NOT NULL default '', UNIQUE KEY code (code) ) TYPE=MyISAM; CREATE TABLE sl_language ( abbrev char(5) NOT NULL default '', date_long char(24) NOT NULL default '', date_short char(24) NOT NULL default '', flag char(48) NOT NULL default '', name char(48) NOT NULL default '', ord int(11) NOT NULL default '0', enable char(1) NOT NULL default 'Y', UNIQUE KEY abbrev (abbrev) ) TYPE=MyISAM; CREATE TABLE sl_posts_cat ( id_posts_cat int(11) NOT NULL default '0', lang char(5) NOT NULL default 'en_US', title char(100) default NULL, description char(255) default NULL, restricted char(1) NOT NULL default 'n', autoapprove char(1) NOT NULL default 'y', ordby char(24) NOT NULL default 'mod_date', lastpost datetime default NULL, ord int(11) NOT NULL default '0', UNIQUE KEY id_posts_cat_idx (id_posts_cat,lang) ) TYPE=MyISAM; CREATE TABLE sl_posts_item ( id_posts_item int(11) NOT NULL default '0', id_posts_cat int(11) NOT NULL default '0', lang char(5) NOT NULL default '', title char(100) NOT NULL default '', comments char(255) NOT NULL default '', approved char(1) NOT NULL default 'n', ins_date datetime default NULL, mod_date datetime default NULL, ord int(11) NOT NULL default '0', UNIQUE KEY posts_item_idx (id_posts_item,id_posts_cat) ) TYPE=MyISAM; CREATE TABLE sl_posts_object ( id_posts_object int(11) NOT NULL default '0', id_posts_item int(11) NOT NULL default '0', id_posts_cat int(11) NOT NULL default '0', object_name char(255) NOT NULL default '', object_mime char(32) NOT NULL default '', object_size int(11) NOT NULL default '0', object_type char(1) NOT NULL default 't', location char(1) NOT NULL default 'c', ord int(11) NOT NULL default '0', approved char(1) NOT NULL default 'n', pic_width int(11) NOT NULL default '0', pic_height int(11) NOT NULL default '0', UNIQUE KEY id_posts_object_idx (id_posts_object,id_posts_item) ) TYPE=MyISAM; CREATE TABLE sl_translate ( id_translate int(11) NOT NULL default '0', msgid char(255) NOT NULL default '', locale char(5) NOT NULL default '', msgstr char(255) default NULL, fuzzy char(1) NOT NULL default 'N', UNIQUE KEY id_translate_idx (id_translate) ) TYPE=MyISAM;
3) Alter and drop table instructions
ALTER TABLE sl_page DROP ord; ALTER TABLE sl_page DROP INDEX name_idx , ADD UNIQUE name_idx (name, is_common); ALTER TABLE sl_project CHANGE name name CHAR(128) NOT NULL; DROP TABLE sl_slotdep; ALTER TABLE sl_module ADD is_common CHAR(1) DEFAULT 'Y' NOT NULL AFTER ord;
4) Populate the language table: select Configure site, and then Resets a table to default (FIXME: this message will be changed soon). Then choose the language table and press OK.
5) Click on Configure site and then on Resets a table to default (FIXME:). Then choose the message table and press OK. Be patient. The operation may take a minute.
Table of Contents
I use this section of the manual to collect code snippets that may be useful for general PHP programming, or within Obliquid framework. They are here as a convenient places to find them without having to dig in old projects source code to find the one needed.
It creates a prononceable password by alternating vowels and consonants. I removed j, k, w, x and y because it's tuned for Italian language that doesn't have these letters. However they can be easily added back in the array below.
/** Creates a pronounceable random password
* @param string $len, optional length (default 8)
* @retrun string the generated password
*/
function make_passwd($len=8)
{
$letter=array(
array("b","c","d","f","g","i","l","m","n","o","p","qu","r","s","t","v","z"),
array("a","e","i","o","u"));
$pass="";
$set=round(rand(0,1));
for ($i=0; $i<$len; $i++) {
$set=!$set;
$idx=floor(rand(0, count($letter[$set])-1));
$pass.=$letter[$set][$idx];
}
return $pass;
}
Checks if an email is formally valid, note that this doesn't mean that such email address exists. There are scripts to connect to a smtp server and test if a user exist faking to send him/her an email, but in my opinion the best way to test if an address works is sending an email there and have the user click some activation url.
/** Checks is the provided email address is formally valid
* @param string $email email address to be checked
* @return true if the email is valid, false otherwise
*/
function valid_email($email) {
$regexp="/^[a-z0-9]+([_\\.-][a-z0-9]+)*@([a-z0-9]+([\.-][a-z0-9]+)*)+\\.[a-z]{2,}$/i";
if ( !preg_match($regexp, $email) ) {
$_obweb->addErr("Email address is not correct\n");
return false;
}
return true;
}
/** Automatic Login.
* Supposing that the user is not signed on, simply redirect to a page
* containing the user slot (may be also only the PHP and not the template)
*/
function login($username, $passwd) {
$goto = & new url();
header("Location: index.php?page=home&action=login&username=".$username."&passwd="
.$passwd."&goto=".urlencode($goto->Build()));
exit();
}
Before optimizing some code, test its execution time, so first you can see if it's worth and second you will see if your changes gave improvements or not. Performance can be not obvious, so don't trust your intuitions. This snippet comes from php.net website: microtime on www.php.net
function getmicrotime(){
list($usec, $sec) = explode(" ",microtime());
return ((float)$usec + (float)$sec);
}
$time_start = getmicrotime();
... code to be profiled here
echo (getmicrotime() - $time_start);
Table of Contents
GNU LESSER GENERAL PUBLIC LICENSE
Version 2.1, February 1999
Copyright (C) 1991, 1999 Free Software Foundation, Inc.
59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
[This is the first released version of the Lesser GPL. It also counts
as the successor of the GNU Library Public License, version 2, hence
the version number 2.1.]
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
Licenses are intended to guarantee your freedom to share and change
free software--to make sure the software is free for all its users.
This license, the Lesser General Public License, applies to some
specially designated software packages--typically libraries--of the
Free Software Foundation and other authors who decide to use it. You
can use it too, but we suggest you first think carefully about whether
this license or the ordinary General Public License is the better
strategy to use in any particular case, based on the explanations below.
When we speak of free software, we are referring to freedom of use,
not price. Our General Public Licenses are designed to make sure that
you have the freedom to distribute copies of free software (and charge
for this service if you wish); that you receive source code or can get
it if you want it; that you can change the software and use pieces of
it in new free programs; and that you are informed that you can do
these things.
To protect your rights, we need to make restrictions that forbid
distributors to deny you these rights or to ask you to surrender these
rights. These restrictions translate to certain responsibilities for
you if you distribute copies of the library or if you modify it.
For example, if you distribute copies of the library, whether gratis
or for a fee, you must give the recipients all the rights that we gave
you. You must make sure that they, too, receive or can get the source
code. If you link other code with the library, you must provide
complete object files to the recipients, so that they can relink them
with the library after making changes to the library and recompiling
it. And you must show them these terms so they know their rights.
We protect your rights with a two-step method: (1) we copyright the
library, and (2) we offer you this license, which gives you legal
permission to copy, distribute and/or modify the library.
To protect each distributor, we want to make it very clear that
there is no warranty for the free library. Also, if the library is
modified by someone else and passed on, the recipients should know
that what they have is not the original version, so that the original
author's reputation will not be affected by problems that might be
introduced by others.
Finally, software patents pose a constant threat to the existence of
any free program. We wish to make sure that a company cannot
effectively restrict the users of a free program by obtaining a
restrictive license from a patent holder. Therefore, we insist that
any patent license obtained for a version of the library must be
consistent with the full freedom of use specified in this license.
Most GNU software, including some libraries, is covered by the
ordinary GNU General Public License. This license, the GNU Lesser
General Public License, applies to certain designated libraries, and
is quite different from the ordinary General Public License. We use
this license for certain libraries in order to permit linking those
libraries into non-free programs.
When a program is linked with a library, whether statically or using
a shared library, the combination of the two is legally speaking a
combined work, a derivative of the original library. The ordinary
General Public License therefore permits such linking only if the
entire combination fits its criteria of freedom. The Lesser General
Public License permits more lax criteria for linking other code with
the library.
We call this license the "Lesser" General Public License because it
does Less to protect the user's freedom than the ordinary General
Public License. It also provides other free software developers Less
of an advantage over competing non-free programs. These disadvantages
are the reason we use the ordinary General Public License for many
libraries. However, the Lesser license provides advantages in certain
special circumstances.
For example, on rare occasions, there may be a special need to
encourage the widest possible use of a certain library, so that it becomes
a de-facto standard. To achieve this, non-free programs must be
allowed to use the library. A more frequent case is that a free
library does the same job as widely used non-free libraries. In this
case, there is little to gain by limiting the free library to free
software only, so we use the Lesser General Public License.
In other cases, permission to use a particular library in non-free
programs enables a greater number of people to use a large body of
free software. For example, permission to use the GNU C Library in
non-free programs enables many more people to use the whole GNU
operating system, as well as its variant, the GNU/Linux operating
system.
Although the Lesser General Public License is Less protective of the
users' freedom, it does ensure that the user of a program that is
linked with the Library has the freedom and the wherewithal to run
that program using a modified version of the Library.
The precise terms and conditions for copying, distribution and
modification follow. Pay close attention to the difference between a
"work based on the library" and a "work that uses the library". The
former contains code derived from the library, whereas the latter must
be combined with the library in order to run.
GNU LESSER GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License Agreement applies to any software library or other
program which contains a notice placed by the copyright holder or
other authorized party saying it may be distributed under the terms of
this Lesser General Public License (also called "this License").
Each licensee is addressed as "you".
A "library" means a collection of software functions and/or data
prepared so as to be conveniently linked with application programs
(which use some of those functions and data) to form executables.
The "Library", below, refers to any such software library or work
which has been distributed under these terms. A "work based on the
Library" means either the Library or any derivative work under
copyright law: that is to say, a work containing the Library or a
portion of it, either verbatim or with modifications and/or translated
straightforwardly into another language. (Hereinafter, translation is
included without limitation in the term "modification".)
"Source code" for a work means the preferred form of the work for
making modifications to it. For a library, complete source code means
all the source code for all modules it contains, plus any associated
interface definition files, plus the scripts used to control compilation
and installation of the library.
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running a program using the Library is not restricted, and output from
such a program is covered only if its contents constitute a work based
on the Library (independent of the use of the Library in a tool for
writing it). Whether that is true depends on what the Library does
and what the program that uses the Library does.
1. You may copy and distribute verbatim copies of the Library's
complete source code as you receive it, in any medium, provided that
you conspicuously and appropriately publish on each copy an
appropriate copyright notice and disclaimer of warranty; keep intact
all the notices that refer to this License and to the absence of any
warranty; and distribute a copy of this License along with the
Library.
You may charge a fee for the physical act of transferring a copy,
and you may at your option offer warranty protection in exchange for a
fee.
2. You may modify your copy or copies of the Library or any portion
of it, thus forming a work based on the Library, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) The modified work must itself be a software library.
b) You must cause the files modified to carry prominent notices
stating that you changed the files and the date of any change.
c) You must cause the whole of the work to be licensed at no
charge to all third parties under the terms of this License.
d) If a facility in the modified Library refers to a function or a
table of data to be supplied by an application program that uses
the facility, other than as an argument passed when the facility
is invoked, then you must make a good faith effort to ensure that,
in the event an application does not supply such function or
table, the facility still operates, and performs whatever part of
its purpose remains meaningful.
(For example, a function in a library to compute square roots has
a purpose that is entirely well-defined independent of the
application. Therefore, Subsection 2d requires that any
application-supplied function or table used by this function must
be optional: if the application does not supply it, the square
root function must still compute square roots.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Library,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Library, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote
it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Library.
In addition, mere aggregation of another work not based on the Library
with the Library (or with a work based on the Library) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may opt to apply the terms of the ordinary GNU General Public
License instead of this License to a given copy of the Library. To do
this, you must alter all the notices that refer to this License, so
that they refer to the ordinary GNU General Public License, version 2,
instead of to this License. (If a newer version than version 2 of the
ordinary GNU General Public License has appeared, then you can specify
that version instead if you wish.) Do not make any other change in
these notices.
Once this change is made in a given copy, it is irreversible for
that copy, so the ordinary GNU General Public License applies to all
subsequent copies and derivative works made from that copy.
This option is useful when you wish to copy part of the code of
the Library into a program that is not a library.
4. You may copy and distribute the Library (or a portion or
derivative of it, under Section 2) in object code or executable form
under the terms of Sections 1 and 2 above provided that you accompany
it with the complete corresponding machine-readable source code, which
must be distributed under the terms of Sections 1 and 2 above on a
medium customarily used for software interchange.
If distribution of object code is made by offering access to copy
from a designated place, then offering equivalent access to copy the
source code from the same place satisfies the requirement to
distribute the source code, even though third parties are not
compelled to copy the source along with the object code.
5. A program that contains no derivative of any portion of the
Library, but is designed to work with the Library by being compiled or
linked with it, is called a "work that uses the Library". Such a
work, in isolation, is not a derivative work of the Library, and
therefore falls outside the scope of this License.
However, linking a "work that uses the Library" with the Library
creates an executable that is a derivative of the Library (because it
contains portions of the Library), rather than a "work that uses the
library". The executable is therefore covered by this License.
Section 6 states terms for distribution of such executables.
When a "work that uses the Library" uses material from a header file
that is part of the Library, the object code for the work may be a
derivative work of the Library even though the source code is not.
Whether this is true is especially significant if the work can be
linked without the Library, or if the work is itself a library. The
threshold for this to be true is not precisely defined by law.
If such an object file uses only numerical parameters, data
structure layouts and accessors, and small macros and small inline
functions (ten lines or less in length), then the use of the object
file is unrestricted, regardless of whether it is legally a derivative
work. (Executables containing this object code plus portions of the
Library will still fall under Section 6.)
Otherwise, if the work is a derivative of the Library, you may
distribute the object code for the work under the terms of Section 6.
Any executables containing that work also fall under Section 6,
whether or not they are linked directly with the Library itself.
6. As an exception to the Sections above, you may also combine or
link a "work that uses the Library" with the Library to produce a
work containing portions of the Library, and distribute that work
under terms of your choice, provided that the terms permit
modification of the work for the customer's own use and reverse
engineering for debugging such modifications.
You must give prominent notice with each copy of the work that the
Library is used in it and that the Library and its use are covered by
this License. You must supply a copy of this License. If the work
during execution displays copyright notices, you must include the
copyright notice for the Library among them, as well as a reference
directing the user to the copy of this License. Also, you must do one
of these things:
a) Accompany the work with the complete corresponding
machine-readable source code for the Library including whatever
changes were used in the work (which must be distributed under
Sections 1 and 2 above); and, if the work is an executable linked
with the Library, with the complete machine-readable "work that
uses the Library", as object code and/or source code, so that the
user can modify the Library and then relink to produce a modified
executable containing the modified Library. (It is understood
that the user who changes the contents of definitions files in the
Library will not necessarily be able to recompile the application
to use the modified definitions.)
b) Use a suitable shared library mechanism for linking with the
Library. A suitable mechanism is one that (1) uses at run time a
copy of the library already present on the user's computer system,
rather than copying library functions into the executable, and (2)
will operate properly with a modified version of the library, if
the user installs one, as long as the modified version is
interface-compatible with the version that the work was made with.
c) Accompany the work with a written offer, valid for at
least three years, to give the same user the materials
specified in Subsection 6a, above, for a charge no more
than the cost of performing this distribution.
d) If distribution of the work is made by offering access to copy
from a designated place, offer equivalent access to copy the above
specified materials from the same place.
e) Verify that the user has already received a copy of these
materials or that you have already sent this user a copy.
For an executable, the required form of the "work that uses the
Library" must include any data and utility programs needed for
reproducing the executable from it. However, as a special exception,
the materials to be distributed need not include anything that is
normally distributed (in either source or binary form) with the major
components (compiler, kernel, and so on) of the operating system on
which the executable runs, unless that component itself accompanies
the executable.
It may happen that this requirement contradicts the license
restrictions of other proprietary libraries that do not normally
accompany the operating system. Such a contradiction means you cannot
use both them and the Library together in an executable that you
distribute.
7. You may place library facilities that are a work based on the
Library side-by-side in a single library together with other library
facilities not covered by this License, and distribute such a combined
library, provided that the separate distribution of the work based on
the Library and of the other library facilities is otherwise
permitted, and provided that you do these two things:
a) Accompany the combined library with a copy of the same work
based on the Library, uncombined with any other library
facilities. This must be distributed under the terms of the
Sections above.
b) Give prominent notice with the combined library of the fact
that part of it is a work based on the Library, and explaining
where to find the accompanying uncombined form of the same work.
8. You may not copy, modify, sublicense, link with, or distribute
the Library except as expressly provided under this License. Any
attempt otherwise to copy, modify, sublicense, link with, or
distribute the Library is void, and will automatically terminate your
rights under this License. However, parties who have received copies,
or rights, from you under this License will not have their licenses
terminated so long as such parties remain in full compliance.
9. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Library or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Library (or any work based on the
Library), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Library or works based on it.
10. Each time you redistribute the Library (or any work based on the
Library), the recipient automatically receives a license from the
original licensor to copy, distribute, link with or modify the Library
subject to these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties with
this License.
11. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Library at all. For example, if a patent
license would not permit royalty-free redistribution of the Library by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Library.
If any portion of this section is held invalid or unenforceable under any
particular circumstance, the balance of the section is intended to apply,
and the section as a whole is intended to apply in other circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
12. If the distribution and/or use of the Library is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Library under this License may add
an explicit geographical distribution limitation excluding those countries,
so that distribution is permitted only in or among countries not thus
excluded. In such case, this License incorporates the limitation as if
written in the body of this License.
13. The Free Software Foundation may publish revised and/or new
versions of the Lesser General Public License from time to time.
Such new versions will be similar in spirit to the present version,
but may differ in detail to address new problems or concerns.
Each version is given a distinguishing version number. If the Library
specifies a version number of this License which applies to it and
"any later version", you have the option of following the terms and
conditions either of that version or of any later version published by
the Free Software Foundation. If the Library does not specify a
license version number, you may choose any version ever published by
the Free Software Foundation.
14. If you wish to incorporate parts of the Library into other free
programs whose distribution conditions are incompatible with these,
write to the author to ask for permission. For software which is
copyrighted by the Free Software Foundation, write to the Free
Software Foundation; we sometimes make exceptions for this. Our
decision will be guided by the two goals of preserving the free status
of all derivatives of our free software and of promoting the sharing
and reuse of software generally.
NO WARRANTY
15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO
WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW.
EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR
OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY
KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE
LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME
THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION.
16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN
WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY
AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU
FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR
CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE
LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING
RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A
FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF
SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH
DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Libraries
If you develop a new library, and you want it to be of the greatest
possible use to the public, we recommend making it free software that
everyone can redistribute and change. You can do so by permitting
redistribution under these terms (or, alternatively, under the terms of the
ordinary General Public License).
To apply these terms, attach the following notices to the library. It is
safest to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least the
"copyright" line and a pointer to where the full notice is found.
<one line to give the library's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Also add information on how to contact you by electronic and paper mail.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the library, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the
library `Frob' (a library for tweaking knobs) written by James Random Hacker.
<signature of Ty Coon>, 1 April 1990
Ty Coon, President of Vice
That's all there is to it!