Jump to content

Invision Community Blog

Login Handlers are the different methods for logging into the IPS Social Suite. We currently support:
"Internal", which is for accounts created natively through the suite. Facebook Twitter Microsoft (this is currently referred to as "Windows Live", though they rebranded to "Microsoft Account" a short while ago) LDAP "IPS Connect", which is our SSO solution for connecting your site with other IPS Social Suite installations or third-party applications. A generic handler for any MySQL database you have access to.

In 4.0 we've made a number of changes to the Login Handlers which I wanted to mention.



Improved Password Encryption

We currently use a salted md5 hash for hashing passwords. md5 has been a popular password hashing technique for years - however, it is not the most secure hashing method.

md5 is designed to be computationally efficient (meaning generating a hash is quick). The problem with this is that if a server were ever compromised to the point that someone were able to gain access to a database containing passwords hashed using md5, and someone were to use a program to generate and hash different strings repeatedly until a match were found, the password could be worked out. One particularly well-known program claims to be able to make 5.6 billion md5 hashes per second with a relatively modern GPU. Even with our hashing method which includes multi-level hashing and a salt, this means, assuming an 8-character long password using only alphanumeric characters were used, a password could be calculated in about 3 days.

While I'm unaware of any cases of this actually happening, we want to make sure that our products are as secure as they can be. For this reason, in 4.0, we're migrating to Blowfish. Blowfish is a more cryptographically secure technique for generating hashes that is deliberately slow, meaning that even if your database were ever compromised, the passwords will still be secure.


New Login Handlers

In addition to the Login Handlers mentioned above, we've added support for Google and LinkedIn.


Improved Facebook and Twitter support

Currently, although you can log in with Facebook and Twitter, they're not treated on the back-end as true Login Handers. This is because of how Login Handlers in 3.x were designed (which was before such 3rd party login services were popular) in that they assumed you would provide a username (or email) and password directly into a form, and subsequently didn't accommodate the OAuth-style login processes.

Since we've rewritten the way Login Handlers are designed, this means we can treat Facebook and Twitter (and Google and LinkedIn which both also use OAuth) exactly the same as the rest.

Practically, this means you'll see Facebook and Twitter in the Login Handlers section of the Admin CP, and manage them as you would any other login method.


Updated Microsoft Support

Microsoft now support OAuth for login through them so we've updated to use that. In addition to being necessary for when they stop supporting the old way, it's much easier to set up for the administrator.
  • 26,147 views
Mark
We've just rebuilt IP.Board 3.4.4 for further beta testing.

Thanks to everyone who has tested this release so far and for reporting the bugs you've found. We've fixed a good portion of these and would like for you to update your test installations with the latest release.

All customers with an active IP.Board license can download the beta at: http://community.inv...ower.com/qa.php

Once you've uploaded all the files to your server, there's no need to run the upgrade system as the version numbers haven't changed. You will need to rebuild your languages and skins. There's instructions here on how to do that.

As always, please report any bugs you find with the beta to our bug tracker.

Please pay particular attention to using the editor with IP.Board 3.4.4. A very large focus was placed on resolving some of the outstanding bugs and complaints with the editor, and we would appreciate any testing you can perform in this area. Create new posts, edit existing posts, toggle between the editor modes - if you find any bugs, let us know.

As with all beta releases from IPS, IP.Board 3.4.4 is not supported by our technicians until it has been officially publicly released. Please do not upgrade your live installation using this beta, as you may find no path between this build and the final release that we put out. We recommended, instead, to create a copy of your live board as a test installation, and upgrade your test installation instead.

Thanks!


  • 7,303 views
Matt
IPS is seeking a knowledgeable and experienced individual to join its support team in an advanced support capacity.

Successful applicants will be responsible for answering general support tickets, including providing customers with information, troubleshooting issues not resolved as part of the general product support process and performing maintenance. You would be expected where appropriate to interact with other technicians and developers to resolve issues.

Requirements:

* Must be familiar with IPS applications.
* Must have advanced knowledge of PHP and MySQL.
* Must be able to effectively work remotely.
* English must be your primary language and you must possess strong verbal and written communication skills.

Preferable, but not required:

* Knowledge of server administration and experience working for a web hosting company.
* Knowledge of additional web technologies such as JavaScript, CSS, XML, etc.
* Experience of working in customer support.
* Experience working with the codebase or creating hooks/apps in the IPS Suite

Working hours are flexible and pay will be based on knowledge and experience. Due to the nature of the position, we require all applicants to be physically located in the United States. No exceptions to United States residency requirements.

Please contact hr@invisionpower.com for more information on this position. Please include your salary requirements, availability and an overview of your experience.

We look forward to hearing from you!

  • 8,799 views
Lindy
IP.Board 3.4.4 is now available for beta testing!

We have been hard at work on IP.Board 3.4.4, and following a good week of testing here on our company forums, we have built a downloadable IP.Board 3.4.4 package for you to test on your own servers. We appreciate any testing you can perform.

Please report any bugs you find with the beta to our bug tracker.

Please pay particular attention to using the editor with IP.Board 3.4.4. A very large focus was placed on resolving some of the outstanding bugs and complaints with the editor, and we would appreciate any testing you can perform in this area. Create new posts, edit existing posts, toggle between the editor modes - if you find any bugs, let us know.

As with all beta releases from IPS, IP.Board 3.4.4 is not supported by our technicians until it has been officially publicly released. Please do not upgrade your live installation using this beta, as you may find no path between this build and the final release that we put out. We recommended, instead, to create a copy of your live board as a test installation, and upgrade your test installation instead.

All customers with an active IP.Board license can download the beta at: http://community.invisionpower.com/qa.php

Thanks in advance! We look forward to your feedback.
  • 39,922 views
bfarber
The eagle eyed among you may have spotted that we've just upgraded our company forums to IP.Board 3.4.4.

We routinely do this during a development cycle so that we can get some extended testing prior to a beta release. When we write new features and fix bugs we do test ourselves but of course we can't replicate the testing hundreds of active users with all the different browser and operating system combinations can offer.

The focus of 3.4.4 has been to further stabilise the editor. We've made great improvements since the initial release of 3.4.0 but we're aware that there are a handful of issues remaining which we want to get licked for this release.

If you have a few moments spare, we'd appreciate it if you could test out the editor, either by creating a post in the test forum or just by being more aware of any quirks or issues when making posts normally.

Anything you spot, can you please report into our bug tracker with as much detail as you can.

Thanks!


  • 9,449 views
Matt
There's a table in the Admin CP of the IPS Social Suite that I really like - the members table. It has some really cool options - you can reorder the data just by clicking on a column head; you can quickly search for a member by typing a name into a search box at the top; there's some filter options to quickly show banned, locked, spam and validating members; and there's an advanced search form to search for members based on practically any criteria.

It would be great if these features were available elsewhere. So much like we did for forms, we decided to create a central helper class for building tables.

To demonstrate how it works, I'm going to go through, step by step, how I recreated the Admin CP members table in IPS 4.


It starts with one line to create the table, and another to pass it to the output class:

/* Create the table */ $table = new IPSHelpersTableDb( 'core_members', 'app=core&module=members&section=members' ); /* Display */ IPSOutput::i()->output = IPSOutput::i()->getTemplate( 'global' )->block( 'members', $table );


With just those two lines, you'll see this:


Some things to note:
We're calling IPSHelpersTableDb - the "Db" part indicates that the source of data for our table is a database table. There are other classes to use, for example, a JSON document as the data source. We pass it the name of our database table (or for the other classes, whatever the data source is) and the query string part of the URL where we're going to be displaying this (which we need to build the links and AJAX calls). I'm passing it to the output through a template called "block" which simply adds the dark-blue bar at the top, which isn't actually part of the table itself, and some padding. The "members" parameter is the key for the langauge string to use in that dark-blue bar. I'm passing $table directly to the template - the helper class has a __toString method which renders the table, so the output class thinks it's been given a normal string.




The first obvious thing is that we're showing all the columns in the database table, which obviously we don't want. So let's add another line to specify which columns we want:
$table->include = array( 'name', 'email', 'joined', 'member_group_id', 'ip_address' );


In this example, I'm giving the helper class a list of columns to include - I could alternatively pass a list of columns to exclude, if that would be more appropriate.

The output is now this:


Some things to note:
It's worked out pagination itself. When you click a pagination link, the contents of the table will update with AJAX, including changing your browser's URL (unless you have JavaScript disabled of course, in which case it will work like a normal link). Pagination defaults to 25 results per page, but you can change that just by changing a property in the class. All the columns are clickable, which will resort the results. You can sort any column ascending or descending. Resorting will also update with AJAX (including changing your browser's URL), unless JavaScript is disabled.




I want the headers to display something more meaningful than the column name. The system will automatically look for language strings which match the column name - you can also optionally specify a prefix, and it'll look for langauge strings which match that followed by the column name.

Let's specify a prefix:
$table->langPrefix = 'members_';

And I'll then create some language strings that match that (so "members_name", "members_email", etc.).

The output is now this:





Next - we need to change how we display some of those values. The joined date and the group are displaying the raw values from the database, but we want something more meaningful than that.

To format the values, we simply create an array of lambda functions - one for each we want to format:


$table->parsers = array( 'joined' => function( $val, $row ) { return IPSDateTime::ts( $val )->localeDate(); }, 'member_group_id' => function( $val, $row ) { return IPSMemberGroup::load( $val )->formattedName(); } );


I'm also going to add one additional line to specify the "main" column, which applies some additional styles:

$table->mainColumn = 'name';


The output is now this:


Some things to note:
I'm using the IPSDateTime class to format the joined date. The ts method in this is a factory method which takes a UNIX timestamp and returns an object of IPSDateTime. IPSDateTime extends DateTime, so all the features of that class are available to us. The localeDate method returns a string with the date formatted appropriately according to user's locale. The IPSMemberGroup::load call being executed for each result may look like it might be resource intensive, but it caches objects it creates, so it's only actually "loading" each group once.





Now I want to add a column with the user's photo. There isn't a single "photo" column in the database we can use for this (since the photo could be one they uploaded, a photo from their Facebook account if they're using Facebook Connect, a Gravatar image, or some other things), we need to use a method in the IPSMember class.

This isn't a problem. I can simply add an element to our list of fields to include and add that into the parsers.
$table->include = array( 'photo', 'name', 'email', 'joined', 'member_group_id', 'ip_address' );

$table->parsers = array( 'photo' => function( $val, $row ) { return IPSMember::constructFromData( $row )->photo('mini'); },

I'll also want to specify that we cannot use the photo column for sorting:


$table->noSort = array( 'photo' );


The output is now this:



Some things to note:
Since this isn't a value which exists in the database, the value of $val in the lambda function will be NULL, however, $row has all the data for that record. We're not using IPSMember::load to get the member object, since that would execute an additional query for every result, which would be resource intensive, and unnecessary since we already have that data. Instead, we use the constructFromData method and pass it the row from the database.




Next, I want to specify the default sorting. This is done with just two lines of code:
$table->sortBy = $table->sortBy ?: 'joined'; $table->sortDirection = $table->sortDirection ?: 'desc';


The output is now this:





Now, I want to add a quick search box. All we need to do is specify which column the quick search should look at:

$table->quickSearch = 'name';


The output is now this:


Some things to note:
As you type, results are obtained with AJAX. You can page through your results (the number of pages will update automatically) and reorder your results by clicking the headers without loosing your search.




I also want to allow more advanced search options - like to search by email address, or joined date. To do this, I create a new array:
$table->advancedSearch = array( 'member_id' => IPSHelpersTableSEARCH_CONTAINS_TEXT, 'email' => IPSHelpersTableSEARCH_CONTAINS_TEXT, 'ip_address' => IPSHelpersTableSEARCH_CONTAINS_TEXT, 'member_group_id' => array( IPSHelpersTableSEARCH_SELECT, array( 'options' => $groups ), function( $val ) { return array( 'member_group_id=? OR ? IN(mgroup_others)', $val, $val ); } ), 'joined' => IPSHelpersTableSEARCH_DATE_RANGE, );


To explain what's going on here:
The keys are the columns we're letting the user search on. The values are usually a constant indicating the type of search that is appropriate for that column. The member_group_id element is a bit more complicated. It has to specify an array of options (I've omitted the code to generate $groups in this snippet, but it'll be at the end of this blog entry), and, because we need to search both primary and secondary groups based on the value, there's a lambda function to get the proper WHERE clause for the query.


Now, next to the quick search box there's a button which will bring up a modal popup (or just take you to a new page if JavaScript is disabled) which looks like this:


Some things to note:The date entry boxes use the HTML5 date input type:

If your browser doesn't support that, there's a JavaScript fallback:

And if you're really awkward and are using a browser that doesn't support the HTML5 date input type and have JavaScript disabled, you'll see a regular text box where you can enter a date in practically any format, and it'll work it out. After performing the search, you can reorder your results by clicking the headers without loosing your search.





Now, I want to add some filters so you can quickly see banned, spam, locked and validating members. To do this, you create an array simply specifying the WHERE clause to use in the query for each filter:
/* Filters */ $table->filters = array( 'members_filter_banned' => 'member_banned=1', 'members_filter_locked' => 'failed_login_count>=' . (int) IPSSettings::i()->ipb_bruteforce_attempts, 'members_filter_spam' => '(members_bitoptions & ' . IPSMember::$bitOptions['bw_is_spammer'] . ') != 0', 'members_filter_validating' => 'v.lost_pass=0 AND v.vid IS NOT NULL' );

For this though, I'll also need to join the core_validating database table, so we add one more line for that:

$table->joins = array( array( 'from' => array( 'core_validating' => 'v' ), 'where' => 'v.member_id=_0.member_id' ) );


The output is now this:


Some things to note:
The helper class will add the "All" filter automatically. It's getting the word to use for the filter by looking for a language string with the same key as the key in the array passed. Like everything else, clicking a filter updates the results with AJAX and the filter is retained in searches.





Finally, the last thing I need to do is add a column with some buttons. You can specify a normal array for buttons to show in the header, and a lambda functions to return an array for buttons to show for each row:
$table->rootButtons = array( 'add' => array( 'icon' => array( 'icons/add.png', 'core' ), 'title' => 'members_add', 'link' => 'app=members&module=members&section=members&do=add', ) ); $table->rowButtons = function( $row ) { return array( 'edit' => array( 'icon' => array( 'icons/edit.png', 'core' ), 'title' => 'edit', 'link' => 'app=members&module=members&section=members&do=edit&id=' . $row['member_id'], ), 'delete' => array( 'icon' => array( 'icons/delete.png', 'core' ), 'title' => 'delete', 'link' => 'app=members&module=members&section=members&do=delete&id=' . $row['member_id'], 'class' => 'delete', ), ); };




Our finished table looks like this:


And behaves like this:
http://screencast.com/t/KMFq8zCE



To recap, here's the code, in it's entirety to generate that table:


/* Create the table */ $table = new IPSHelpersTableDb( 'core_members', 'app=core&module=members&section=members' ); $table->langPrefix = 'members_'; /* Columns we need */ $table->include = array( 'photo', 'name', 'email', 'joined', 'member_group_id', 'ip_address' ); $table->mainColumn = 'name'; $table->noSort = array( 'photo' ); /* Default sort options */ $table->sortBy = $table->sortBy ?: 'joined'; $table->sortDirection = $table->sortDirection ?: 'desc'; /* Filters */ $table->joins = array( array( 'from' => array( 'core_validating' => 'v' ), 'where' => 'v.member_id=_0.member_id' ) ); $table->filters = array( 'members_filter_banned' => 'member_banned=1', 'members_filter_locked' => 'failed_login_count>=' . (int) IPSSettings::i()->ipb_bruteforce_attempts, /*@todo*/ 'members_filter_spam' => '(members_bitoptions & ' . IPSMember::$bitOptions['bw_is_spammer'] . ') != 0', 'members_filter_validating' => 'v.lost_pass=0 AND v.vid IS NOT NULL' ); /* Groups for advanced filter (need to do it this way because array_merge renumbers the result */ $groups = array( '' => 'any_group' ); foreach ( IPSMemberGroup::groups() as $k => $v ) { $groups[ $k ] = $v; } /* Search */ $table->quickSearch = 'name'; $table->advancedSearch = array( 'member_id' => IPSHelpersTableSEARCH_CONTAINS_TEXT, 'email' => IPSHelpersTableSEARCH_CONTAINS_TEXT, 'ip_address' => IPSHelpersTableSEARCH_CONTAINS_TEXT, 'member_group_id' => array( IPSHelpersTableSEARCH_SELECT, array( 'options' => $groups ), function( $val ) { return array( 'member_group_id=? OR ? IN(mgroup_others)', $val, $val ); } ), 'joined' => IPSHelpersTableSEARCH_DATE_RANGE, ); /* Custom parsers */ $table->parsers = array( 'photo' => function( $val, $row ) { return IPSMember::constructFromData( $row )->photo('mini'); }, 'joined' => function( $val, $row ) { return IPSDateTime::ts( $val )->localeDate(); }, 'member_group_id' => function( $val, $row ) { return IPSMemberGroup::load( $val )->formattedName(); } ); /* Specify the buttons */ $table->rootButtons = array( 'add' => array( 'icon' => array( 'icons/add.png', 'core' ), 'title' => 'members_add', 'link' => 'app=members&module=members&section=members&do=add', ) ); $table->rowButtons = function( $row ) { return array( 'edit' => array( 'icon' => array( 'icons/edit.png', 'core' ), 'title' => 'edit', 'link' => 'app=members&module=members&section=members&do=edit&id=' . $row['member_id'], ), 'delete' => array( 'icon' => array( 'icons/delete.png', 'core' ), 'title' => 'delete', 'link' => 'app=members&module=members&section=members&do=delete&id=' . $row['member_id'], 'class' => 'delete', ), ); }; /* Display */ IPSOutput::i()->output = IPSOutput::i()->getTemplate( 'global' )->block( 'members', $table );


  • 19,804 views
Mark
One question I have seen surface in the past (and present), revolves around how we decide when to use a third party library or framework, and how we decide when to develop something in-house entirely. For instance, in the 4.0 Suite we will utilize jQuery (a third party javascript framework), however we will build our underlying PHP framework in-house. How did we decide to go that route? There are several PHP frameworks on the web, many of which having licenses compatible with our commercial license, so why didn't we choose one of those to kickstart 4.0 development?

This is, admittedly, often a difficult question to answer. The truth is, we evaluate each scenario on a case-by-case basis and make decisions based on what is best for us and our clients. Sometimes these decisions may not be obvious, however you should know that much thought has gone on behind the scenes here at IPS to ensure we are making the choices that we feel are best for our products.

Javascript frameworks are almost an essential tool with today's fast-paced browser development and web advances. Browser updates from some vendors are almost weekly. We went from HTML 4 to XHTML 1 to HTML 5 within but a few years. And while everything a javascript framework does can be replicated in-house, it would consume a lot of development time that we would have to spend in order to keep pace with all of these changes, purely for compatibility reasons (e.g. no new functionality added, just to keep things working and up to date). We have long-ago determined that using a well-maintained javascript framework to facilitate javascript development is virtually a necessity, otherwise you quickly get bogged down trying to maintain javascript code just to retain compatibility with current browsers and newly available functionality.

What about PHP frameworks though? There are many out there (CodeIgniter, Zend Framework, etc.) and many are relatively robust, well tested and quite extensible. Why have we chosen to write our own underlying framework given this information? In researching whether to maintain our own framework or use an existing one, we had to weigh many pros and cons. For instance, one pro using third party PHP frameworks would be that we can skip all of the development of underlying classes (controllers, autoloaders, database connector and so forth) and jump into the higher level development. This is surely an important consideration to take into account.

On the other hand, using third party PHP frameworks ties us into that framework, and we expect the underlying codebase in the 4.0 series to last several years once it is released. What if the framework we choose to utilize is no longer maintained 2 years from now? What if a security issue arises in the third party framework, but it is not rectified quickly? We certainly can't leave our clients vulnerable to known security vulnerabilities while we wait for a third party to patch it. What if the framework developers release an important update, but it renders APIs incompatible with our implementation of the framework? We could find ourselves in a situation where we either can't update the framework easily, or we would need to recode many of the underlying usages of the framework in order to update. Additionally, frameworks often have many, many capabilities, many which we may not need or use. This can make our release larger than it needs to be, and/or cause our software to consume more resources than it would otherwise, if those features which we aren't using were not present. Of course, licensing concerns are also present - we have to be certain that any third party code we use is released under a license that is compatible with our commercial license. Finally, if we utilized a third party PHP framework, we would either have to (1) rewrite ALL of our code (just think of every database query that may be run - these would need to be passed through the framework rather than through our own database driver), or (2) write an abstraction layer on top of the framework to translate the requests we currently send to low-level classes so that they are compatible with the framework. No easy task, either way.

By writing our own framework we ultimately have better control of our software. We can tailor every class to our needs, ensuring that it is as efficient as possible within the confines of what we wish to accomplish, while still making these classes robust enough to handle everything we want to throw at it. We can ensure we do not have unnecessary classes and code, or features which aren't (and never will be) used. If a security issue is found, we have full control over the underlying code base and can address the issue quickly without waiting on a third party to release an update, or rewriting underlying API calls in our software if the framework changes how a class must be called. If we wish to implement new functionality, we can implement these changes directly in low-level classes efficiently. We do not have to work within the third party framework's design, artificially requiring us to utilize more resources (e.g. by extending a class vs implementing our changes into the base class to start with).

By writing our own framework, we face the "con" of spending the time up front to develop all of these low level classes we will need, however we feel the "pros" that this affords us in the long run are worth the time and trouble. It is a decision every developer or development company has to make as they approach a product, and everyone has different view points. The take away here, however, should be that we have indeed looked into available options, weighed the pros and cons against our goals and needs, and have determined after careful evaluation that sometimes it is best to use an existing framework, and sometimes we just need to roll our own.
  • 10,549 views
bfarber
When developing, modifying the database schema (such as adding a column to a table) can be surprisingly time consuming. Currently, we have to:
Make the change locally Change the installer Add the query to make the change to the upgrader for whatever version we're working on Let the other developers know so they can run the query to make the change in their installs.


This can cause issues, especially at the last step - we currently use a large .sql file in the trunk directory of our repository which we add queries to that we need everyone else to run - sometimes, one of us doesn't notice this has been updated. I'm sure also, third party modification authors are familiar with this annoyance.


In 4.0, one of the things I really wanted to do was build a central "Developer Center" from which both us and modification authors can manage aspects of the application without digging into installer/upgrader files, XML files and manually copying and pasting things when creating a new module or extension.

Part of this developer centre is a GUI for modifying the database schema. When you make changes, the changes will automatically be ran against your local database and added into the installer and upgrader. Internally, we'll also then have a special script which runs when we SVN update to copy these changes over when another developer makes a change.


The first page in the Database Schema Management will be a list of tables:


You can add a table to the list either by creating a new table, importing a table which is already in the database or uploading a .sql file containing a CREATE TABLE statement:




When you edit a table, you can manage the columns, indexes and rows which are inserted by default:


If you try to edit a table and your local database does not match what the schema has, you'll be shown the conflicts:




This, plus the other features in the Developer Center, which we'll talk about in later blog entries, make the process of developing applications easier for both us, and third party authors.




Fun fact: I'm writing this blog entry from the home of IPS in Lynchburg, VA rather than my usual office in the UK :smile:
  • 10,020 views
Mark
Forms are an ubiquitous aspect of any web application. In the IPS Social Suite, particularly in the Admin CP, I often find myself copying and pasting code in various places to create a form. We've had the ipsRegistry::getClass('output')->formInput() and similar methods since 3.0, but you still have to copy all the HTML to display the rows, and write all the code to validate it yourself.

Copying and pasting code is something all developers hate. It's a red flag that you're probably doing something wrong. In IPS 4.0, we've written a central form building helper class to alleviate this.

Just as a reminder: Everything in this blog is a work in progress - naturally someone with a much keener design sense than I will be going over the interface - I'm just demonstrating the functionality, not a finished product :smile:


The Basics

Let's say I want to create a form with a single text input field. I simply initiate the form, add an object representing the input, and then display the form (it has a __toString method) - like so:

$form = new IPSHelpersForm(); $form->add( new IPSHelpersFormText( 'name', 'default value' ) ); IPSOutput::i()->output .= $form;


The helper will automatically look for language strings with the same name as the form element and use them. If there is a language string with the same name and then "_desc" - it'll use that as the description.

So the above code, in the ACP, produces something like this:



Required

Let's say I want the field to be required - I just pass a third argument indicating so. When the form is submitted, if no value has been provided, it will automatically display an inline error:



new IPSHelpersFormText( 'name', '', TRUE )






Options

The fourth argument I can pass is an array with options dependent on the type of input field I'm adding. These options may change the way a field is displayed or add additional validation.

So for a text field, I can specify the minimum and maximum length (which, naturally takes multibyte languages into consideration):



new IPSHelpersFormText( 'name', '', TRUE, array( 'minLength' => 5 ) )




For a number field, I might specify the number of decimal points to round to, which it will do on the fly:


new IPSHelpersFormNumber( 'name', 0, TRUE, array( 'decimals' => 2 ) )

Watch Video


Or I could add an "Unlimited" checkbox, which is quite common for Admin CP settings:

new IPSHelpersFormNumber( 'name', 0, TRUE, array( 'unlimited' => TRUE ) )




Custom Validation

If the built-in options don't provide enough validation for a given need, you can pass a lambda function as a 5th argument:


new IPSHelpersFormText( 'name', '', TRUE, array(), function( $val ) { if ( $val === 'Bad Value' ) { throw new IPSHelpersFormException( 'That value is not allowed.' ); } } )




Uploads

Of course - simple input fields aren't all that can be done. How does drag and drop uploading sound?


new IPSHelpersFormUpload( 'name', NULL, FALSE, array( 'multiple' => TRUE ) )

Watch Video

(By the way, you'll notice a stripy bar flashes up briefly - this is a real progress bar, but because I'm uploading to localhost it's filling faster than it displays - in practice, you'll see a nice smooth-filling progress bar)


Getting the values

The form helper will by default (you can override it of course) submit to the same page it's on. You can check if it has been submitted (and passed validation) and obtain the values if so simply by calling the values() method - here's an example:


$form = new IPSHelpersForm(); $form->add( ... ); if ( $values = $form->values() ) { // $values contains the values from the form } else { IPSOutput::i()->output .= $form; }


The values will be returned in a way that is appropriate to the input type. For example, a text input field will return a string, number input will return either an integer or float, an upload field will return an IPSFile object (or array of them, if you're accepting multiple files), etc.
  • 10,816 views
Mark
Development is much more than just opening a text editor and writing some code. This is how most developers start, of course, and may be what an individual developer's day to day duties entail at a large corporation, however when viewing the "big picture" there are many other decisions that must be made in the course of building a software package for release that clients often don't realize were even considered. We thought you might be interested in hearing about some of those decisions that were made regarding 4.0, prior to ever writing a single line of code.


Minimum Supported Versions
One decision that has to be made relatively early in the development process is what dependencies will the software require. For software developed in PHP, this typically means what version of PHP will be the minimum, and (often) what will be the minimum required version of MySQL.

PHP 5.3.0 was released in June of 2009, and includes functionality that we intend to utilize within the 4.0 Suite. Subsequently, this was an easy decision to make.

We were leaning towards requiring MySQL 5.5, which was also released in 2009. We feel that 3 years is long enough on the web to incorporate updated software within most hosting environments. Upon investigating the functionality we intend to utilize in MySQL, however, we have determined that MySQL 5.0.3 and above includes everything we need, so MySQL 5.0.3 will be our minimum required version.


Profiling and Benchmarking
If you are a PHP developer and have ever attempted to profile your code, you probably realize it can be challenging. Many IDEs support some level of profiling built in, however it is almost always manually invoked. xdebug is a powerful tool for profiling, but again it requires you to enable profiling, run a request, and then view the results. In a live environment this is nearly impossible as profiling adds a lot of overhead to page loads and creates hundreds of profiling files quickly.

Our goal is to be able to profile changes as they are committed, right away. We have decided to install Zend Server to the server that will host our staging environment for 4.0, which supports automatic rule-based built in profiling. This will allow us to easily profile requests automatically, even those that we may not "know" how to trigger manually (e.g. a specific task in a specific circumstance takes a long time to execute).


Improving automatic deployments
While automatically building and deploying the software to our staging environment itself is not a challenge per-se, a lot of times changes occur that require some sort of manual intervention to enact. We may have exported updated skin templates, language files, or there may be SQL queries that need to be run. We are developing an automatic deployment routine that can handle all of this easily and programatically, ensuring our staging environment is truly always up to date with the latest changes.


Website and forum organization
Not directly related to 4.0, another area we had to consider was our organization on the website and on our community here. This extend to all areas of the community, from the organization of our feedback and support forums, to our marketplace categorization, to our bug tracker categorization. The approach with 4.0 will be that we have one suite with modular applications that can be enabled. We need to market the software this way, and we need to ensure that the logical work flow for our clients reflects how our suite is designed. You will be seeing changes to categorization throughout our sites based on 4.0 in due course as a result.


Loose ends
And beyond all of the stuff directly related to 4.0, we felt it prudent to tackle a lot of loose ends before we jumped into a major overhaul of our entire software line up. There were a lot of smaller tasks that have been pushed off for a while but which we've finally sorted through which we feel will afford us less distractions as we work on the next release. Most of these tasks were minor, but not unimportant. Examples include:
Moving our documentation to the main website Improving minor areas of IP.Downloads and IP.Nexus to allow clients to better help themselves, or to allow a smoother work flow within the administration areas our employees utilize every day Scripts on our end that allow us to better manage certain services Cleaning up old content in our installation, such as removing unused IP.Content blocks and deleting left over files on our server


None of this directly affects 4.0, however the less distracted we get with minor tasks during 4.0 development, the better we can focus and deliver the product in a timely manner and with less chance of distraction-related bugs.


Of course hundreds of other decisions have gone into 4.0 as well, some of which we will talk about in future blog entries. We thought you might be interested in hearing about some of the smaller things us developers do here at IPS, however, besides developing great software products to power your communities!
  • 7,049 views
bfarber
In 4.0, we have made changes to the database class to make use of prepared statements.


For insert and update queries, the syntax is the same as it always has been:

IPSDb::i()->insert( 'table', array( 'foo' => 'bar' ) );

However, where previously the database class would try to work out the type of variable passed to it - it now binds these to a prepared statement.

The real usefulness of this change though, is apparent when you need to use a where clause. Where previously you'd have to do something like this:

$this->DB->buildAndFetch( array( 'select' => '*', 'from' => 'table', 'where' => "foo='" . $this->DB->addSlashes( $foo ) . "'" ) );
You can now do:

IPSDb::i()->buildAndFetch( array( 'select' => '*', 'from' => 'table', 'where' => array( 'foo=?', $foo ) ) );
We calculate the datatype based on the variable datatype, so previously where you had to do things like $this->DB->setDataType( 'foo', 'string' ) when you wanted to store a value like '01' - ew) - you can now just cast the variable to whatever datatype you like.
For example, if you wanted to ensure that the variable was cast as a string to avoid issues where a user name of '007' was detected as an integer and converted to '7' then you'd use:

IPSDb::i()->buildAndFetch( array( 'select' => '*', 'from' => 'table', 'where' => array( 'foo=?', (string) $foo ) ) );
Not only is this easier to type and to read, it ensures that the database class always takes care of escaping things properly.
  • 8,391 views
Mark
We have built public beta releases of our entire product line up for testing. Please be aware that beta releases are not supported by IPS technical support. We do not recommend running them on a live site, you may be unable to upgrade from a beta release to the final version, and our only course of support is to recommend you restore a backup of your site if you face any issues.

We appreciate clients who wish to participate in beta testing programs. We would recommend cloning your live site, or installing these betas to a new test environment, in order to test the bug fixes and functionality improvements. Please report bugs in the bug tracker. As of the time of this post, our company forums are running all of these latest versions.

IP.Board 3.4.3
Bug fixes


IP.Blog 2.6.2Bug fixes


IP.Calendar 3.3.2Bug fixes


IP.Chat 1.4.3Bug fixes


IP.Content 2.3.5Bug fixes


IP.Downloads 2.5.3Bug fixes Multiple featured files now supported Ability for clients to manage renewals for purchased files now supported


IP.Gallery 5.0.4Bug fixes Ability to create Gallery IP.Content feeds filtering on "featured" status now supported


IP.Nexus 1.5.7Bug fixes Integration with the bulk mailer supported Ability to leave a customer note when voiding account added



You can download beta releases for which your license gives you access to at our QA page. Thanks in advance to all who decide to test!
  • 6,649 views
bfarber
This is just a quick update to let everyone know of a small enhancement you can expect to see in the next IP.Gallery release.

We recently noticed that you could not create IP.Content feed blocks to pull featured images from IP.Gallery. We felt that this was a small and easily correctable oversight, so we added a filter option when creating IP.Gallery feed blocks in IP.Content to allow you to choose whether to pull only featured images or not. You can expect to see this new option beginning with the IP.Gallery 5.0.4 release.

Adding filters to IP.Content feed blocks is a generally easy process, depending upon what you are trying to filter by. Naturally, some types of filters can make the block much more complex, but with the example above of filtering by retrieving featured images, we needed only 2 language strings and 10 distinct lines of code.

What types of block filters have you always felt would be easy but useful additions?
  • 6,532 views
bfarber
A while back, we casually mentioned in a blog entry that 4.0 would be next major version after 3.4. Development of 4.0 is underway and we're going to be using this new blog to talk about development as we go.

As Brandon mentioned a couple of days ago - the format of these entries is going to be developer-specific. If what we're saying doesn't make much sense right now, we will still be putting announcements up in our main blog when they're finished and ready for everyone to see.

Because of that, it's also worth bearing in mind that everything is subject to change. I'm going to be posting code samples, screenshots and so forth - but everything in this blog is a work in progress - not the final product - and that will probably show.

With that out the way - let's talk about 4.0! :D



The file structure

Currently, applications are mostly self contained in their folders (which is either /admin/applications, /admin/applications_addon/ips or /admin/applications_addon/other) however, other files are dotted around in /interface, /public, etc. In 4.0, applications will be completely self-contained within a single /applications directory.

An application directory will look something like this:
extensions dev
css html img js lang

admin front (it's "front" rather than "public" now)

[*]interface [*]modules[*]setup [*]sources [*]tasks [*]xml
You will notice the inclusion of a /dev folder. This will not actually be shipped in production, but rather replaces /cache/lang_cache/master_lang and so forth in the 3.x line.

Outside of the applications directory, there will be a "system" directory, which contains core framework classes.


Namespaces and autoloading

In 4.0, we'll be making use of PHP namespaces and using an autoloader. The best way to demonstrate how this works is with a few examples:classDb (/ips_kernel/classDb.php) is now IPSDb and located in /system/Db/Db.php output (/admin/sources/classes/output/publicOutput.php) is now IPSOutput and located in /system/Output/Output.php class_forums (/admin/applications/forums/sources/classes/forums/class_forums.php) is now IPSforumsForum and located in /applications/forums/sources/Forum/Forum.php IPSDispatcherFront and IPSDispatcherAdmin are two new classes (with similar functionality to ipsController in 3.x) and both extend IPSDispatcherDispatcher - all 3 are located in /system/Dispatcher/ in individual files.


Better framework design

Where appropriate, classes are being refactored to make better use of appropriate design patterns. One lovely side-effect of this is ipsRegistry no longer exists.

Instead of, for example ipsRegistry::DB() you now use IPSDb::i() - the Db class uses a multiton design pattern (I didn't pass any arguments in that example, which doing will cause the Db class to load conf_global.php and create the default database connection, but I could have passed it a key) - the i method in this case will create the database connection if it doesn't already exist.

To give another example - IPSMember (the new IPSMember) uses an Active Record pattern. So there's no more of this:
IPSMember::isInGroup( 1, 4 );
It's now, the much more logical:
IPSMember::load( 1 )->isInGroup( 4 );


Monkey patching hooks

One of the great things about the IPS Community Suite is hooks - you can easily create a class and instruct the framework to use that instead of a core class.

Now, I don't know about you, but I really, really, really hate having to do this:
$class = IPSLib::loadLibrary( '/path/to/file', 'myClass' );
$object = new $class;

Especially if what you want to call is a static method, in which case it can't be done. You want to of course, just be able to do:
$object = new myClass;
or:
myClass::myStaticMethod();

There is a concept in software engineering to do this sort of thing, called monkey patching, and by clever use of the autoloader, we've managed to make this work. loadLibary and loadActionOverloader are no more.




These points are of course, just the beginning of 4.0. Stay tuned for more :smile:
  • 11,390 views
Mark
While we introduced some of our basic plans for 4.0 many months ago, we wanted to touch base again on some of these plans and expand upon some of our motivations behind decisions we have or will make for our upcoming 4.0 software release.

Before we get too far, let me just state now that there is no expected (or even estimated) release date for 4.0 yet. While we always have internal guidelines, timeframes and milestones, we do not communicate these publicly until we are absolutely sure they are as accurate as possible. The 4.0 Suite will be a major overhaul, effectively a rewrite of most areas from the ground up, and there are many factors that can affect delivering within expected due dates.

You may also have noticed the title of this blog entry uses a term for the suite you may not have seen used previously. We have decided to name the 4.0 Suite (which we will often refer to as "4.0 Suite" or "Social Suite", informally), officially as the IPS Social Suite. We feel that as we expand our line up and remove community-related dependencies, it is important that our main product release reflect the fact that our software can power more than just traditional communities.

Formalities out of the way now, here are a few of our driving motivations behind 4.0...

Modernize the interface
The skin delivered for 3.0 and again for 3.2 was great, but several years have since passed. It is time we modernize the user interface in our software lineup once again. Features have been added, trends on the web have shifted, and technologies have advanced. Some specific points you may be interested to know:
All areas of the suite will support the mobile interface. We are heavily investigating using a "response design" for 4.0. We will be switching to jQuery We will be embracing HTML 5 fully


Modernize the underlying codebase
While 4.0 will not technically be a "complete rewrite", most of the underlying codebase will be rewritten in some manner, and all of the code will at least be updated to work within the new framework we are developing. There is a lot to go over for those of you who may be interested in the developer side of things, and I'll point you to the right place later in this entry, but as a general outline here are some things you can expect to see:PHP 5.3 will be the minimum supported version of PHP MySQL 5.0.3 will be the minimum supported version of MySQL IP.Board will fully utilize namespaces in PHP The entire directory structure, class naming structure and more will be completely overhauled Applications will truly be self-contained within their own folders (currently javascript, skin and language files, for instance, are scattered throughout miscellaneous directories) The entire code base will be modernized. More use of formal design patterns will be employed, where appropriate. Dumping ground classes (such as IPSLib) will be avoided at all costs. More consistency between how applications implement functionality will be seen. Naming conventions will be more consistent. The way hooks work will be completely rewritten, making things simpler for us and for developers, and making hook usage behind the scenes more reliable (no more loadLibrary calls - everything is handled automatically by the framework instead).


Make things more consistent
We are also working towards making all of our applications more consistent. The approach to this actually has much more to do with planning and how we approach new functionality than it does any specific technical aspect of software development. In a nutshell, we will have one "suite" release moving forward starting at 4.0. Every application will be on the same versioning system and share the same version number, and every release will include every application (although you will only have access to the applications you have purchased, of course). What we will do as we implement new features is implement new functionality suite-wide from the start. If we were to add a new feature to 4.0, we would not add the functionality to the forums and then roll this change out to other applications as they see updates. Instead, we will be implementing changes suite-wide from the start, which has several benefits:From a user standpoint, the software will be more consistent. You won't have situations where a feature is available in Application X but not in Application Y. From a technological standpoint, we will be forced to implement functionality in an optimal manner where it can be utilized by all areas of the suite. There will be less application-dependencies for features that are intended to be suite-wide. There will be much, much less duplicated code as features will be designed from the start to work in multiple areas. Point #2 above will also benefit modders - APIs will be much more robust, yet more generic and reusable, for features implemented suite-wide rather than features implemented for one application and then shared across others.


Beyond changing our approach to functional changes in the software itself, we will also be focusing on consistency while redesigning the interface, and throughout every facet of development of 4.0.


Want to hear more specifics?
We have recently launched our new development blog where we will routinely be posting about the nitty-gritty of our day to day development duties here at IPS. While this blog is not at all intended to be specific to the development of 4.0, you will find us posting about upcoming changes and decisions made in 4.0 quite regularly. We welcome you to follow The Development Channel blog if you are interested in reading about these changes. If not, don't worry - any major announcements will be blogged about here in our company blog as well in due course.

If you aren't sure, just to be clear....development of 4.0 is definitely underway. A lot of planning and discussion took place prior to ever writing a single line of code for 4.0, however we are definitely working on 4.0 now and you will likely see blog entries about upcoming changes before long. Stay tuned!
  • 34,960 views
bfarber
Through use of our own marketplace, we often identify small but useful changes to IP.Downloads that benefit sites that both use IP.Downloads to allow distribution of free files as well as those that sell files through a marketplace. While working to improve the user interface of the home page in IP.Downloads, we decided that allowing multiple featured files would be a small change but would help improve the interaction and discoverability of useful content in the marketplace. After all, every other marketplace has more than one file featured, right?

IP.Downloads 2.5.3 will now allow you to feature more than one file. Up to 20 of the most recent files that are marked as featured will display on the homepage in a carousel-style panel. The act of featuring a file has not changed (the only thing that has changed here is that other files which are featured are no longer automatically unfeatured). Only the homepage interface has really changed.

Here is a short video to show you what it looks like with two featured files. Note that if you only have one featured file, it will display as it does now in IP.Downloads 2.5.2.

http://screencast.com/t/A0KX6uWs

You will note that you can manually cycle through featured files, or they will cycle automatically. If you mouse over the featured file panel, the automatic cycling pauses.

We hope you find this small change useful, and more consistent with other applications that allow featuring (such as IP.Blog, where you can feature more than one entry, and IP.Gallery, where you can feature more than one image). Let us know what you think in the comments below!
  • 7,412 views
bfarber
We identified a use case recently where we wanted to send a bulk mail to all clients who had purchased a particular package in IP.Nexus. This is not uncommon. Perhaps the package is being discontinued. Perhaps you erroneously over charged for this package. Perhaps there will be a special on additional purchases of this package. Regardless of the reason, it is logical and ordinary that you want to email all clients who have purchased a given package.

Because the bulk mailer was improved in 3.4 and now supports per-application extensions, we have written one for IP.Nexus 1.5.7 that allows you to control with the bulk mailer certain ways to filter members based on packages they have purchased.

The way this works is very simple. When you go to send a new bulk mail, there is now an IP.Nexus tab in the filters area allowing you to filter by IP.Nexus purchases. You can also control whether you send to only active purchases, expired purchases, cancelled purchases, or any combination there-of. Here is a screenshot to show you what it looks like on our site:



I'm sure you can see just how valuable this small but useful change will be. This enhancement will be available with the release of IP.Nexus 1.5.7.

What other types of filters have you wanted to bulk mail members utilizing, but can't presently?
  • 6,677 views
bfarber
Our marketplace is an area where developers can submit free and paid resources for other clients to download and use on their website. IPS processes many, many transactions through the marketplace, both one-off purchases and renewals for applications clients have previously purchased.

When an application has renewals, however, it was pointed out that the client had no way to cancel those renewals. Perhaps the client is no longer using the resource they purchased, for instance, and does not wish to renew the purchase any longer. With our product releases in the client area you can easily opt not to renew purchases if you want, however there has been no way to do this in the marketplace...until now.

With the release of IP.Downloads 2.5.3 (and available in the marketplace now), instead of a button that reads "Buy another", the button has been relabeled to "Manage Purchases". When you click this button on a file you have purchased, you will still have the option to purchase more licenses, however you will also have the ability to manage your existing purchases, includingCanceling a purchase that is active Reactivating a previously canceled purchase Renewing a purchase that has expired


Additionally, we enhanced IP.Downloads so that when an author changes a paid file with renewals to free that it clears out the renewal terms for any clients who have purchased the file. If the file is no longer paid and no longer has renewals, existing purchases should not still renew, after all. And finally, if the file name is changed, previous purchases that are displayed in a user's client area will now reflect the updated file name, for clarity.

These small enhancements will make clients better able to manage their purchases, save our customer service representatives time by not requiring them to cancel purchases for clients, and provide an all around more robust and complete experience for users.



(Please be aware that this is an early screenshot of a feature to be included in the next release of IP.Downloads, and subsequently the interface and display is subject to change)
  • 6,208 views
bfarber
We have launched our new blog The Development Channel to allow our development staff to more frequently update our clients on everything that goes on behind the scenes. From the technical aspects, to fun insights, and new feature announcements you can follow The Development Channel to follow our software being made.
  • 10,541 views
Charles
Hello everyone!

Us developers are a strange bunch. We have a lot of crazy thoughts that just don't make sense to anyone else. Our brains are wired different. We get from point A to point B by going around point Z and bouncing off point M first. And very few of us (*cough*me exempted*cough*) are able to type up posts that make sense to more than just other developers.

So what are we to do? Keep all of our great thoughts to ourselves? Nonsense. Nevertheless, we cannot flood everyone with the semi-(in)sane ramblings that go on in our heads every day, nor can we bore everyone with discussions of how great our new class structure will be, or how useful the new methods we've just added to x class will turn out.

Introducing The Development Channel

This blog will be a place us developers can write up our thoughts and discuss developer-specific topics. Anyone can follow this blog if they want to. We're not out to have a private exclusive group that only the elite development community can join. Quite the contrary - if you are interested in the sorts of things us developers do on a regular basis or are interested in the future and development of the software, please feel free to follow this blog. We will be talking about new features, minor tweaks and other changes to existing features, code-level improvements (such as class structure, class inheritance, and so on) and even things not related to the software (think: how we do x on our website, or why we chose to approach a problem in a specific way). If any of this is your cup of tea, we hope you enjoy the blog entries to follow. If this is all Greek to you (and you don't speak Greek), then by all means - ignore us. You are certainly free to continue following our official News forum and our official Company Blog, where all the important stuff will get posted.

If you're still here, we hope you enjoy what we have in store. :)
  • 4,106 views
bfarber
We have added a minor enhancement to IP.Nexus 1.5.7 that we thought you might be interested to hear about.

Our customer service representatives found that when they "voided" an account in IP.Nexus (by clicking the "Void Account" button when viewing the customer screen in the ACP) that they often wanted to leave a customer note at the same time, explaining why the account was voided. For years they simply added the customer note manually after they voided the account. This isn't a big deal, but we identified a way to improve their workflow in this instance.

With the release of IP.Nexus, a textarea box has been added to the "Void Account" page (as long as you have permission to leave customer notes), allowing you to leave a customer note at the same time you void the account. This small change will save our customer service representatives time and effort while they perform their daily routines, and took us less than half an hour to do!



Have you found any small changes like the one identified above that would save you time and effort? Sometimes moving a button around or adding an extra form field can make all the difference!
  • 49,467 views
bfarber
Last year, we added an auto-install/upgrade tool into our client area. The tool would upload the latest version of the IPS Community Suite to your server automatically.
The way it worked was after submitting the request, you were entered into a queue, and a program on our server uploaded the files, and emailed you when it was done so that you could run the upgrader script. It normally took about 30 minutes.


30 minutes is pretty good. For someone without the technical knowledge to upgrade, it's a great alternative to asking for a support agent to do the upgrade for you (especially just after a release when everyone is doing just that). However, many users still prefer to do the upgrade themselves (after all, if you can download the source files and upload them to your server in the same time, what's the point?).


We decided we should try and get that time down. We also wanted the process to be much more seamless - so you click "Upgrade", get a loading screen, and then are taken immediately to the upgrade script when it's done, rather than waiting for an email.



Interested to see how fast we managed to get it? Take a look for yourself:
Watch Video




In addition, the system can now handle communities that have renamed their admin directory seamlessly without issue (it previously reset to /admin), and the system will automatically detect which encoding of IP.Nexus to use for your server, if applicable (previously it would only use Zend).




We really hope the Auto-Upgrader will provide a much easier way for you to keep your community up-to-date with the latest features and enhancements.


If you've not already upgraded to IP.Board 3.4, why not go and try it out now? To access the tool, simply go to the Purchases area of the client area, select the community you want to upgrade and click the big "Upgrade Now" button.
  • 17,881 views
Mark
We are happy to report some really dramatic improvements to the IPS Converters. If you have been considering switching to IPS from another community software now is the time.

Performance Improvements

One area for improvement we focused on was the overall time it took to do a conversion. Doing a conversion is always going to be a time consuming process as it involves translating all of your data from your old format to IPS format. But we have made two big improvements:

MySQL queries, where possible, now do one 'extended' query rather than thousands of smaller queries. This means your data is fetched in one, large batch and stored rather than many smaller batches.

The member conversion routine has been sped up dramatically. Some test conversions are seeing an 80% speed increase on members alone.

Example statistic: 15 million post community converted 1000 posts a second and about 800 topics a second. Converted completely in 4 hours. The old converter could take more than a day to do the same. That's a huge improvement!

Software Specific Improvements
vBulletin Subscriptions now directly import to IP.Nexus Gallery 5 support Photopost 8 support XenForo 'likes' converted. XenForo personal conversations converted. vBulletin conversions now use the same forum/topic/post/member IDs on IPS Community Suite. This is great for SEO.


Feedback Appreciated

We are continuing to work on improvements to our converters. If you perform a conversion please submit a ticket and let us know of any issues you might experience so we can assist you.

Special Switch Promotion

If you are considering switching to the IPS Community Suite we would welcome you as a new IPS client. We are happy to provide 10% discount on new license purchases using the coupon code SWITCH at checkout. This coupon code is valid until 15 December 2012.

With the recent release of IP.Board 3.4 now is a great time to take another look at IPS!
  • 9,429 views
Charles
It's an unfortunate fact that when you run a successful site, you attract unwanted users posting spam on your site. IP.Board has always been incredibly pro-active in preventing spam users from signing up by making use of built in tools such as the question and answer challenge, spam monitoring service and CAPTCHA systems.

I'd like to take a moment to talk about some enhancements we've made in IP.Board 3.4.0 to help prevent unwanted posts and spam.

Spam Monitoring Improvements

We've further enhanced the spam monitoring service in IP.Board 3.4.0 by adding a new option: "Do not permit the user to register an account". This reduces the amount of clean up you need to do after a new wave of attempted spam user sign-ups.

Furthermore, the "flag a member as a spammer" tool optionally deletes posted content rather than simply hiding them further reducing the amount of work needed to maintain your community.



We have also totally reworked our spammer-detection logic behind the scenes to make the spam monitoring service detect spammers more quickly. In addition to internal changes, we are also looking at direct integration with services like Project Honey Pot and others. The great thing about the spam monitoring service is that we can make improvements on our side that are instantly beneficial to your community.

keyCAPTCHA Integration
IP.Board has made good use of the popular reCAPTCHA service to limit the number of "bots" that sign up to your forum with the intent of posting spam. The idea being that a slightly jumbled selection of letters is easy enough for a human to read but more difficult for a computer program. However, some do find that the CAPTCHA images are becoming increasingly complex to keep up with more intelligently written programs to defeat them.

KeyCAPTCHA takes a novel approach to this problem by using images instead of letters and numbers. You simply arrange a few large pieces of a very simple puzzle to complete an image.



You don't need to be completely accurate when building the image, either.



This is now an option in the IP.Board Admin CP. Should you wish to enable it, you'll need to register an account with keyCAPTCHA. The link for this is contained in the setting form and is very straight forward.

As always, we look for new ways to help make running your community a little easier and we look forward to helping you keep those spammers at bay!
  • 34,402 views
Matt