The integration of some products with others, especially if they are not intended for this, is rarely carried out with white gloves. Usually, at least in my experience, it is necessary, having rolled up our sleeves, to crawl into this and another product, study its code, write hacks, tamp one with the other. Rarely docking can be carried out in separate files, even less often in classes, with templates it is also all difficult, especially if there are no templates. Usually such code is tightly frozen and brings problems when updating products, often making them impossible or very complicated. In the article I would like to tell you how I had to integrate other products into the portal on Bitrix - a photo gallery, a forum and a chat.
Although, for me in this regard, it is rather surprising that, for example, forums, which in their sense will most likely be attached to portals, do not provide integration tools or at least do not provide for potential possibility in their code. In my opinion, it is not so difficult to take out the templates separately, configs and initialization code so that it can be easily connected from other places. Yes, and global variables that have scattered about the edge of mind - is it difficult to make a separate namespace for them or a separate class with static variables? Well, if absolutely you can’t do without them, you can at least put them in a corner so that you don’t stink, and periodically get them when you need them. However, the logic takes its own way - the code was written a long time ago, no one wants to dig into it, it works - don’t bother, and the business doesn’t understand either - what do you spend time on? You better implement a new feature, and I'll chop it with attendants. So it lives. But, rather, Earl, you are carried away. To the point.
Bitrix Very nice.
In one of the wonderful days I received an assignment for a new project. The portal was written a long time ago, has been maintained at the administrative level since then, and it was necessary to breathe new life into it. The tasks were set by a person who was quite far from programming and IT in general, and therefore they came down mainly to changing menu items, changing the appearance and so on. True, all the tasks were almost non-negotiable and should have been completed at any cost. I could easily sincerely ask me: “Why not search immediately on the portal and on the forum? There's also a search form, what does she look for everywhere? How can we make her look everywhere? ” And such an innocent, from their point of view, task would have to be realized. I looked at the scope of work and went to get acquainted with the project.
')
I saw a portal on bitrix. The usual such information portal, with little functionality, is quite old. As a separate product, a photo gallery, a forum and a chat were attached to the portal, which in design from a distance resembled a portal, but were not integrated with it in any way. For all elements of the portal, among other things, there was the same task - to bring them to the same appearance, namely, to add a standard cap and basement from the bitrix. If we lived in an era of prosperity, where all people would be equal, a sausage would cost 2p.20kop., And all software products would be written taking into account the latest trends of the PLO, the task would turn into an easy educational walk on the patterns of these products and a ten-minute writing inherited class or template connection. But then it would be boring to live. As usual, the bitrix amused me to the fullest.
Threat analysis.
So, first a small materiel for those who for some happy reason have not yet had time to get acquainted with the bitrix from the inside. The logic and representation in it are separated only in components, the core as a whole has retained its structure from earlier versions, and therefore everything is mixed together.
Typical page on Bitrix looks like this:
<?require_once $_SERVER['DOCUMENT_ROOT'].'/bitrix/header.php'?>
.
<?require_once $_SERVER['DOCUMENT_ROOT'].'/bitrix/footer.php'?>
At the same time in the header and the basement of the page goes the bitrix logic, including the rendering templates. In order to be able to write logic in the user script that will control the display in the template, the bitrix uses the so-called delayed call functions. They have been repeatedly written about (for example,
here or in the Bitrix documentation), and therefore I will not be distributed once again. Such functions require buffering, and therefore in the header call, a buffer is opened to absorb the contents, and in the basement the buffer is closed and its contents fall out into the stream.
Bitrix is ​​unique in its own way, and when you want to understand how some part of it works, it's usually better to go straight into the code. If you do not immediately vomit, you can sometimes find very interesting things. Documentation is good, but not always there you can find what is required. And since the bitrix is ​​not intended for integration with other products (I do not mean 1C), you will have to finish it with your hands. So, put on a gas mask and dive.
We swim close - to the file /bitrix/modules/main/include/prolog_before.php. And we see there is a block of code that is responsible for buffering:
if(COption::GetOptionString("main", "buffer_content", "Y")=="Y" && (!defined("BX_BUFFER_USED") || BX_BUFFER_USED!==true))
{
ob_start(Array(&$APPLICATION, "EndBufferContent"));
$APPLICATION->buffered = true;
define("BX_BUFFER_USED", true);
}
<Offtop>
By the way, in version 7 you can then see this line:
register_shutdown_function(create_function('', 'while(@ob_end_flush());'));
For what I love the bitrix, so for the fact that it does not relax and keeps in tune all the time.
</ Offtop>
And an interesting question arises. It turns out that there is some buffer_content setting that signals whether to buffer content. It is noteworthy that it is not configured through the admin area, and in the standard zero base (if you install the pure bitrix) is missing. Therefore, the default value, in this case, “Y” is taken. And what will happen if it is added and set to “N”? We make our way into the base, into the b_option table and start it there. Then we clean the folder / bitrix / managed_cache and try to write scripts. Everything, more content is not buffered. True, the ability to change the appearance of the header from the page, for example, title, is lost. But here you have to choose what is more important.
You can set the setting using the methods of the bitrix itself, namely the COption :: SetOptionString method. However, be careful, it does not work as expected. It seemed logical to me if the settings with its help are set for the duration of the script execution in the same way as the ini_set function. However, this method just sets the setting right in the database. Imagine if you would have worked ini_set - included error_reporting (E_ALL) for your script there - and the entire hosting went down. So, we learned how to enable / disable buffering, let's go further.
Warm up
The first client in the queue is the gallery.
Here the case is quite simple - just connect the cap. However, due to the predilection for global variables from both products, a love triangle happened here: a bitrix, a photo gallery and a global variable $ USER. And so I had to remove it unset. The situation, however, is quite typical when integrating products that for some reason persistently refuse to use OOP and encapsulation. Well, God forgive them. With a basement, everything is also quite simple - just pull out the global variables (only $ APPLICATION was needed here) via global $ varname, and then the bitrix will be offended and fall: he thought that once he declared such a variable in the header, he would find it in the basement but no.
Stern forum.
The second case is more advanced - the forum vbullentin. It is remarkable because, firstly, it is paid, and therefore you won’t get into the autogen code, and secondly, because it was also written by harsh men with beards (who wants to feel all their power, you can try to understand the search script on the forum).
The script did not register the connection to the template, because the template engine is your own and it does not execute php code. The only thing he can do is replace one php variable with another. I had to use it, since there is no other. To fill such variables, the forum allows you to write hacks (hooks) on php, and then execute them on certain events (eval, of course). One of the events was quite suitable, so it was quite possible to hook the cap there. The problem was that the hack was executed before the template was output, and therefore it was necessary to buffer the output of the Bitrix Header. That is, the wedge wedge knock out. At first I tried for a long time in an amicable way, honestly tried to close the buffer opened by the bitrix, but all my attempts were in vain - here I could not overcome it. If someone succeeds, lay out, please - I'm interested to see how it is tamed.
Therefore, I decided to take drastic measures and disable buffering using the buffer_content parameter in the manner described above if the forum render is in progress. That is, we had to add the following code to the /bitrix/php_interface/init.php script:
if(strpos($APPLICATION->GetCurDir(), '/forum/') === false)
COption::SetOptionString("main", "buffer_content", "Y",'','ru');
else
COption::SetOptionString("main", "buffer_content", "N",'','ru');
Of course, crooked and unpleasant, but it works. Now it was possible to simply buffer both the header and the basement until the rendering of the templates of the forum itself. Namely:
ob_start();
include('bitrix/header.php');
$bitrixheader = ob_get_clean();
Similarly with the basement. And then output the $ bitrixHeader variable into the template. Of course, this was not done without unset global variables, but these are trifles.
Step 3. Same perl.
Well, for a snack - chat. This option turned out to be the toughest, since it was not even that there were difficulties with the bitrix. A chat on a pearl, written in 1996 with inserts of 2002, is laid out in the same style (framesets, no styles, the properties are written in tags), the data in txt files, not a single hint of patterns, output in a continuous stream, well although there were some functions - all this, you know, inspired. Yes, and its appearance caused a desire to close the page, but here it is not arguing about tastes - users like it, and right. It was necessary to make inserts there in the only way - to start php console, execute a script and display the result. After the Bitriksov caps or basement are executed, the script ends and, therefore, the buffer is output to the stream, and there are no problems with this. The only subtlety was that since the script was executed console, it was necessary to include the Bitriksovsky initial and final scripts in a special way, however, the
official documentation quite tolerably tells about it. The main problems with the chat arose because of its terrifying structure and respectable age, and also because I saw the pearl for the first time in my life. I was so impressed that I would now be wary of opening pearl-barley scripts. The result was such a terrible monster that you would not look without tears - you had to add a separate frame and display the cap there. And also spawn a few hacks, when the pearl-barley script calls a php-script, which inside itself causes another barley ... After finishing the work, I wanted to wash my hands and hand over the work to Kunstkamera. govnokod.ru resting.
Conclusion
That's how one of the bitrix integrations went through. Surprised, by the way, that despite its popularity, there are no extensive materials on setting it up for yourself and sharpening with a file - I found only a few scraps. And even more so, his integration into third-party forums, because his native forum is clearly inferior to others. If you have something to share in this regard - you are welcome, it will be interesting to know.
Special thanks to
bioroot for perl tips and moral support in a difficult task.