This is a 100% score solution in matter of correctness and performance for the first exercise of the leader lessons section on Codility.com, as I am a web developer I’ve used javascript in order to achieve this result. Here’s the exercise description on Codility:
An array A consisting of N integers is given. The dominator of array A is the value that occurs in more than half of the elements of A.
For example, consider array A such that A[0] = 3 A[1] = 4 A[2] = 3
A[3] = 2 A[4] = 3 A[5] = -1
A[6] = 3 A[7] = 3
The dominator of A is 3 because it occurs in 5 out of 8 elements of A (namely in those with indices 0, 2, 4, 6 and 7) and 5 is more than a half of 8.
Write a function
function solution(A);
that, given an array A consisting of N integers, returns index of any element of array A in which the dominator of A occurs. The function should return −1 if array A does not have a dominator.
For example, given array A such that A[0] = 3 A[1] = 4 A[2] = 3
A[3] = 2 A[4] = 3 A[5] = -1
A[6] = 3 A[7] = 3
the function may return 0, 2, 4, 6 or 7, as explained above.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [0..100,000];
each element of array A is an integer within the range [−2,147,483,648..2,147,483,647].
Using a counter for each number on the array
In order to find if a specific number is a dominant or not we need to count how much it occurs in the A array right? that means that we need some kind of a counter, but since there’s not one but many different numbers in the array then we’ll need as much counters as the distinct numbers of the array that’s why I created a counter in a form of an array and named it counters, the idea is to dedicate a cell for each of the array’s distinct numbers, so if we come across the number 3 for example then we’ll simply do the following:
counters[3]++
of course, this is in the case where we met 3 for the second time, otherwise we need to give the cell a default value before we increment it (we can’t increment an undefined variable)
if(typeof counters[3]==”undefined”) counters[3]=1
when we loop on our main array A and calculate each distinct number occurrences we’ll end up with an array containing the counters of all those numbers but we’re still unable to tell which number is the dominant unless we create a second loop or use the max function to get which counter is the greater, this will work but will definitely cost us in performance leading to a lower result than 100% that’s why I am not looping on the counters or using the max (reduce) function in this solution. Instead, I simply check if one of the counter has reached the half+1 condition, if it is true, the loop stops and returns the current index of the number of which the counter is greater than half+1
if(counters[current]>A.length/2) return i
Here’s the solution in full:
function solution(A) {
var counters=[]
for(var i=0;i<A.length;i++){
var current=A[i];
if(typeof counters[current]=="undefined")
counters[current]=1
else
counters[current]++
if(counters[current]>A.length/2)
return i
}
return -1;
}
If you’re looking to get a full score in matter of correctness and performance in the fourth exercise of the Stacks and Queues lessons on Codility (StoneWall) then you’ve come to the right place, before we begin here’s the full exercise description from Codility:
You are going to build a stone wall. The wall should be straight and N meters long, and its thickness should be constant; however, it should have different heights in different places. The height of the wall is specified by an array H of N positive integers. H[I] is the height of the wall from I to I+1 meters to the right of its left end. In particular, H[0] is the height of the wall’s left end and H[N−1] is the height of the wall’s right end.
The wall should be built of cuboid stone blocks (that is, all sides of such blocks are rectangular). Your task is to compute the minimum number of blocks needed to build the wall.
Write a function:
function solution(H);
that, given an array H of N positive integers specifying the height of the wall, returns the minimum number of blocks needed to build it.
For example, given array H containing N = 9 integers: H[0] = 8 H[1] = 8 H[2] = 5
H[3] = 7 H[4] = 9 H[5] = 8
H[6] = 7 H[7] = 4 H[8] = 8
the function should return 7. The figure shows one possible arrangement of seven blocks.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..100,000];
each element of array H is an integer within the range [1..1,000,000,000].
Understanding the StoneWall exercise
I had to read the exercise description multiple times before understanding it and it was because of the figure
when I saw it at the first time I had the wrong idea that those blocks are actually elements from the H array (the heights) which led me to a confusion I got rid of as soon as I understood the origin of those blocks. the exercise is actually quite simple and the best way to explain is to take the same example given in the exercise description:
In this example, the wall should be 9 meters long ( H.length ) and each meter of the wall can have a different height, for example the 3rd meter (H[2]) is a 5 meters height ( H[2] = 5 ) Don’t forget that the array H only contains the heights of each meter of the wall but what we actually need in order to get this exercise done is a way to calculate the blocks you see in the figure above which are still to be determined so let us first understand what are those blocks and why are they placed the way they are in the figure. if you take the first block on the left of the figure you may notice that it has a 2 meters width and 8 meters height, that’s because both H[0] & h[1] have the same value (8) and they have no other height that precede them since they’re the two first elements of the array H, now to explain this further, it is not necessary to place two blocks of the same height as it takes 1 single block to build the two first meters of the main wall.
if for example, H[1] had a different value (height) then it would have taken two blocks to build the first two meters of the main wall because a block must have the same height all along its width. now if you look at the other blocks of the figure you might get confused because the wall could have contained a different configuration of blocks while keeping the same blocks number( in other words the minimum number of blocks needed to build the wall) and that’s correct and could be done too but if the blocks are placed the way they are in the figure it’s because they simply have been placed in compliance to a specific algorithm. just think of it like if, each time we add a block to the wall, we try to make it as wide as possible, so if we take the last block and the one before:
They corresponds to H[7] & H[8) (4 & 8 meters), they could have drawn a block of 4 meters height followed by a block of 8 meters height both having a width of 1 meter, but instead, the first block is 2 meters long and it in order to reach a 8 meters height in the last meter of the wall’s length they’ve added a second block of 4 meters placed above the previous one, so by doing so they made sure the first block has taken as much width as possible while respecting its initial height. so by following this rule you will ensure that each new block is going to take as much space as possible before a newer block is going to take place and by doing so each block isn’t only going to contribute to raise the wall’s height in its initial position but may contribute in the height of the following ones as well reducing so the number of block needed to meet the height of each column and in the end you’ll get the minimum number of blocks needed to build the wall.
A solution with a time complexity of O(N)
Enough with the explanations, the following code does exactly what I have described above
function solution(H) {
var blocks=1
var previousWall=[H[0]]
var previousHeight=H[0];
for(var i=1;i<H.length;i++){
var currentHeight=H[i];
var heightDiff=currentHeight-previousHeight;
if(heightDiff>0){ //current wall heighter
blocks++
previousHeight+=heightDiff
previousWall.push(heightDiff)
}else{
while(previousHeight>currentHeight){
var lastBlock=previousWall.pop()
previousHeight-=lastBlock;
}
heightDiff=currentHeight-previousHeight;
if(heightDiff>0){ //current wall is highter
blocks++
previousWall.push(heightDiff)
previousHeight+=heightDiff
}
}
}
return blocks
}
If you think you have a better or easier solution don’t hesitate to share it with me in the comments below
In this post I am going to talk about a 100% score javascript solution to the second exercise of the Stacks & Queues lesson named Fish
Now here’s the exercise’s description on Codility:
You are given two non-empty arrays A and B consisting of N integers. Arrays A and B represent N voracious fish in a river, ordered downstream along the flow of the river.
The fish are numbered from 0 to N − 1. If P and Q are two fish and P < Q, then fish P is initially upstream of fish Q. Initially, each fish has a unique position.
Fish number P is represented by A[P] and B[P]. Array A contains the sizes of the fish. All its elements are unique. Array B contains the directions of the fish. It contains only 0s and/or 1s, where:
0 represents a fish flowing upstream,
1 represents a fish flowing downstream.
If two fish move in opposite directions and there are no other (living) fish between them, they will eventually meet each other. Then only one fish can stay alive − the larger fish eats the smaller one. More precisely, we say that two fish P and Q meet each other when P < Q, B[P] = 1 and B[Q] = 0, and there are no living fish between them. After they meet:
If A[P] > A[Q] then P eats Q, and P will still be flowing downstream,
If A[Q] > A[P] then Q eats P, and Q will still be flowing upstream.
We assume that all the fish are flowing at the same speed. That is, fish moving in the same direction never meet. The goal is to calculate the number of fish that will stay alive.
For example, consider arrays A and B such that: A[0] = 4 B[0] = 0
A[1] = 3 B[1] = 1
A[2] = 2 B[2] = 0
A[3] = 1 B[3] = 0
A[4] = 5 B[4] = 0
Initially all the fish are alive and all except fish number 1 are moving upstream. Fish number 1 meets fish number 2 and eats it, then it meets fish number 3 and eats it too. Finally, it meets fish number 4 and is eaten by it. The remaining two fish, number 0 and 4, never meet and therefore stay alive.
Write a function:
function solution(A, B);
that, given two non-empty arrays A and B consisting of N integers, returns the number of fish that will stay alive.
For example, given the arrays shown above, the function should return 2, as explained above.
Write an efficient algorithm for the following assumptions:
N is an integer within the range [1..100,000];
each element of array A is an integer within the range [0..1,000,000,000];
each element of array B is an integer that can have one of the following values: 0, 1;
the elements of A are all distinct.
Before we elaborate, here’s the full javascript solution in case you’re just coming for the code:
function solution(A, B) {
function processFish(fish){
for(var i=survivors.length-1;i>=0;i--){
var lastFish=survivors[i]
if(lastFish>0 && fish<0) {//last fish is going down
if(Math.abs(lastFish)<Math.abs(fish)) {// fish is bigger
survivors.pop()
if(i<=0){
survivors.push(fish)
break;
}
}
else
break; //do nothing
}
else{
survivors.push(fish)
break
}
}
}
function addFish(i){
if(B[i]>0)
var fish=A[i]
else
var fish=-A[i]
if(survivors.length==0)
survivors.push(fish)
else
processFish(fish)
}
var survivors=[]
addFish(0)
for(var i=1;i<A.length;i++){
addFish(i)
}
return survivors.length
}
this solution gives a score of 100% in matter of correctness and performance and has a time complexity of O(N)
Using a stack to determine the number of surviving fish
In order to calculate how much fish are left in the end, we need to create a stack and fill it with all the surviving fish, one at a time
survivors.push(fish)
each time a fish is added to the stack it may devour one or more of the survivors in case the conditions are met, so in case the upcoming fish is meant to eat the last fish of the stack, we’re simply going to remove the prey (the last fish of the stack):
survivors.pop()
in the opposite case (the last fish of the stack is eating the upcoming fish) we’re simply going to do nothing. Once we’re done with collecting the surviving fish in a stack, we just need to return its length which will gives us the exact number of fish that will stay alive
return survivors.length
Now we need to build the logic around this base, that is to say making sure to properly interact with the survivors array according to the description of the exercise
Combining arrays A & B (sizes and directions of the fish) into one
Since we need two criterias to determine which one of a two given crossing fish is going to survive we are given two arrays, one contains the size of each fish while the other is containing the direction but we don’t really need to rely on two arrays ! In fact, a single array would be easier to manage then two so that why combining the two arrays is a good idea. We can keep note of the direction plus the size of a fish using a simple method: we make sure to use the size of the fish as the value and we make it a negative number if the fish in question is going upstream, on the other hand, if the fish is floating downstream we just keep the number positive. Example: -5 would represent a fish floating upstream that has a size of 5 so first step is to loop on the fish list:
for(var i=1;i<A.length;i++){
addFish(i)
}
Second, we combine each fish’s size and direction into one value:
if(B[i]>0) // if current fish is floating downstream
var fish=A[i]
else //upstream
var fish=-A[i]
Combining happens at the same time as filling the survivors array so that performances are kept minimal. By combining the size and the direction the one dimension survivors array becomes enough to keep note of each fish in case we have to return to it later.
Filling the stack
Now we just need to write the logic that will determine how to deal with each fish passed by the previous loop. Testing the outcome of two fish crossing each other becomes simple now that we have the direction and size into a single variable so to test if a fish is going upstream or downstream we just compare it to zero:
if(fish<0)
//fish is floating upstream
else
//downstream
and to test which fish is bigger we just need to compare their absolute values
Math.abs(fish1)<Math.abs(fish2)
To start, we need to loop on the stack. Remember: once we introduce a new fish to the stack we need to make sure to check if it’s going to eat one or more of the survivors we collected before ! of course the first fish that’s going to be attacked if the conditions are met is the last element of the stack, once eaten we keep moving to the previous one until we find another fish that floats in the opposite direction and then either: -our fish is bigger: in this case we remove the last fish from the stack or.. -the last fish is bigger: we stop the loop and bring up a new fish from the remaining ones. if when looping on the stack we reach one of these cases: -the beginning of the stack -a fish going in the same direction (upstream) We insert the new fish in the stack and it becomes the last fish
for(var i=survivors.length-1;i>=0;i--){
var lastFish=survivors[i]
if(lastFish>0 && fish<0) {//last fish is going down
if(Math.abs(lastFish)<Math.abs(fish)) {// fish is bigger
survivors.pop()
if(i<=0){
survivors.push(fish)
break;
}
}
else
break;
}
else{
survivors.push(fish)
break
}
}
Once the loop on the fish is done, we gets an array containing all the fish that survived, again all you have to do here is to return its length
This solution may bring a 100% score but I am sure there’s an alternative with less lines of code, if you think you have this alternative and it has 100% score then don’t hesitate to share it with me as I am curious to see which approach you have followed.
have you ever been in a situation where you need to get all the elements that gets inserted into a web page after it has been loaded? like when a new html content has been loaded using ajax then appended to a web page’s body. In this tutorial we’re going to write a custom jQuery event that will trigger anytime an html element is added to our webpage, the event will return a list of all the new elements in a variable that we can use on the callback function like we used to do on any regular jquery event method. So our event method will look like:
So you just need to copy this code and past it at the beginning of your javascript, of course it goes without saying that you need to call the jQuery library before doing all of this.
One of my colleagues asked me if it was possible to create a dynamic counter that automatically prints a different number each time the document is printed on Microsoft word, the point was to have a unique serial number on each print, of course one can manually create multiple numeric copies of the same document and change the serial number on each copy then print all those documents, but in my case my colleague was planing to print out 36000 copy of the same document, the content should remain the same on all the 36000 copies, the only thing that changes is the serial number which he would insert somewhere in the document so he would see something like 00001, 00002, 00003… on each printed document so now imagine the time it would take to create and change that number manually on 36000 files ! that’s enormous and inevitably requires automating. My colleague thought I could use my programming skills to create a sort of macro that would do the trick but I honestly have no past experience with VBA and god thanks I didn’t start looking to write a vba script because there was a quite easier solution I am going to share with you in this article.
Generate a serial number using Word Mail merge and Excel
the solution to insert and increment automatically a counter on word is to use a feature that’s initially made for a different purpose so this solution is actually a turnaround but still it’s way easier than writing a vba macro.
the final result will be a doc file containing as many pages as you want, each page will contain a unique number right in the location you would previously specify before you generate the final result.
As an example let’s suppose I want to print 10 pages where each page contains a number that will increment on each print, so my pages will have 01, 02, 03, …10. Here’s the steps :
1. Create an Excel file containing the serial numbers
With Excel you can easily create a formula that will generate all the possible serial numbers that we’ll need for the following steps, here’s how to do it: -create a new Excel file -pick the first cell (top left A1) and type the initial number, 1 in my case
-chose the column below (A2) and insert this formula in it: =SUM(A1;1)
-Now you just need to reproduce the same thing on the whole column until you reach the maximum number of serials you want to general (10 in my case), this can be done by dragging the small black tile on the bottom right of the selected cell (A2) and moving the mouse down until reaching the desired cell.
this will automatically apply the increment formula on all the selected cells:
-save the document somewhere on your desktop and keep excel aside for now.
2. Import the Excel file on word using the mail merge feature
-open the document you want to print using Microsoft word, at this stage the document is still not containing the serial number. -look for the mail merge button, you should find it in Mailings > Start Mail Merge > Step by step mail wizard…
-On Select Document Type chose Letters
-click on Next (bottom right) until you reach step 3
-On step 3 click on Select a different list and chose the Excel file we created previously
-Multiple windows are going to show up, just click on ok then move to step 4 by clicking Next -On step 4 click on More items
-A window is going to appear containing the only column available on your Excel file. by clicking insert this will place the counter variable name right where your cursor is positioned in your document. You can insert the variable name then simply cut/paste it where you want, or you can simply position your cursor on the desired location before opening that window, both ways are fine.
-close that window and keep clicking Next until you reach the 6th step
3. Print !
Now that you’ve gone through the steps, your pages are ready for printing, you can verify your documents are fine before you proceed to printing by clicking on Edit individual letters then you can simply Print
As a store owner you may start thinking of creating an additional domain name for your store in order to attract more visitors, if you came to think about this idea then you’d probably want to keep the same store along with the same products, categories & extensions… for both your domains which makes total sens but this isn’t as simple as creating and pointing your new domain to the same directory as your old domain, in fact your homepage may show up at first on the new domain but you will notice that the store is incomplete or wrong, if you see missing icons, corrupted images or links that still points to the old domain then be sure that you haven’t configured your OpenCart to handle the new domain correctly. This tutorial will help you get your store showing up the same way for your secondary domain or any additional domain name that you might want to add later.
I am assuming that you’ve already gone through the new domain creation process and that you have pointed it to the same server directory as your old domain. so if your new domain is mysecondsite.com then you’re supposed to see your old homepage when you go to that url before starting on this tutorial.
Create a new store on your OpenCart admin panel
Login to your admin panel and go to System > Settings there you can find your stores list:
Now you need to create a new store by clicking the top right blue plus button, just fill the new store’s information and make sure that the store name ends up by a slash ( / ), so if your site is mysecondsite.com you should input: http://mysecondsite.com/ Once this step is done, you should at least see a change on your new domain, one of these is changes is that all your products or categories are gone, this isn’t bad because it means the new domain is finally pointing to the right store. we’ll see how to restore all of those in the following steps.
Assign your products and categories to the new store
now the new store created we need to make sure it has the same content as the old store, so to understand how OpenCart manages each store’s content, it simply consider a two different stores like if their stocks are separate from each other but still allow you to assign it to more than one store at a time and you can do that by going to the data tab of your product or category, in other words go to catalog > categories chose a category then access the data tab then under stores just check the store you want to assign the category to but you need to manually do this for each product and category and of course, if you’re here then you must be looking for an automatic solution in order to assign all your products and categories to the new store once and for all so that’s what we’re going to take care of in the following steps. if you don’t see any section named Stores then don’t worry about this so just ignore this part.
Now in order to show all your previous categories and products on the new domain you need to execute some MySql queries on your database, so access your database manager (ex: phpmyadmin) through your host panel then go to the table oc_store and note the store_id of the new domain
in my example the store_id is 2, you’re going to need this number in the following steps
after that simply execute the following queries on your database manager and don’t forget to change the store_id value which is ‘2’ in my queries, if your store id is 3 then simply replace ‘2’ by ‘3’
INSERT INTO `oc_category_to_store`(`category_id`,`store_id`) SELECT `category_id`,'2' FROM `oc_category_to_store` WHERE `store_id` = "0"
INSERT INTO `oc_product_to_store` ( `product_id`, `store_id`)
SELECT `product_id`, '2' FROM `oc_product_to_store` WHERE `store_id` = '0';
these queries will automatically assign all your products and categories to your new store and you should be able to see them now.
My whole life I’ve been spending a considerable percentage of my web development projects time dealing with errors rather than enjoying the coding part. Rare are the projects I had to accomplish without coming across an unexpected error or bug. Sometimes the fix is easy and other times it is a hopeless cause. Especially when you’re working with a framework like OpenCart.
It’s not uncommon to me to face a familiar issue that I managed to correct in the past. I can simply apply the same fix. The problem is, I have to remember how I fixed it in the first place. This has made me mad more than once but today I am putting an end to it. I decided to write this page as a way for me to keep note of the issues I face the most on OpenCart and how I fixed them, in the second plan, I hope it will save the time of some of you so you can spend it on a more productive work.
I will keep updating this page each time I come across a common Opencart issue and fix it.
OpenCart Installation & Update Issues:
1.Install infinite loop
if you searched this on Google then you’ve come to the right place:
this is how your url looks like if your OpenCart store is stuck in infinite loop during install:
These issues happen mostly when you open your OpenCart store url for the first time. Like when you try to install OpenCart or upgrade it to a newer version. The store enters in an infinite redirect loop and ends up by displaying a ERR_TOO_MANY_REDIRECTS error page. But in some rare cases this can suddenly happen to your store even if it has been running before. In this case you should preferably try to restore your website to a previous backup or find out what has changed since the last working version.
This issue is supposed to happen only when one is trying to install or upgrade opencart which means that you may have lost some important files on your OpenCart directory, or what’s left from your store is maybe pointing to the wrong location. if you get this issue upon install or update then this is how to deal with it:
Browser re-directions cache:
Make sure your browser’s cache isn’t interfering. Clear it up, or try on a different browser or a different device. Just begin by testing your page as far as possible from your usual browser. if you obtain a different result then focus on clearing your browser’s cache before you proceed further. Browser’s cache can still interfere when you try the following steps too so keep in mind that you need to clear your cache each time you try a new solution. You don’t want to pass by the solution because of this ridiculous exception.
Try adding “upload” to the url
if you’re trying to install OpenCart using this url: yoursite.com then try accessing it from here instead: yoursite.com/upload If it works then you’ve done something wrong when you extracted the installation compressed file. So stop just there because that installation has been made on a wrong basis. You probably placed the folder upload inside your store’s root directory. What you have to do is simple: move all the upload folder’s content to the parent directory. In other words move all the upload folder’s files to your store’s root directory
disable the .htaccess file temporarily
This file may contain some redirection rules that causes a conflict which prevents the installation process from starting correctly. look for the file and disable it by renaming it temporarily. Some ftp clients hides it by default so you need to perform an extra step in order to find it. it should be in the directory of your store.
2.Uncaught TypeError: Argument 2 passed to Event::trigger() must be of the type array, string given..
this is the full error message:
Fatal error: Uncaught TypeError: Argument 2 passed to Event::trigger() must be of the type array, string given, called in xxx/system/storage/modification/system/engine/loader.php on line 140 and defined in xxx/system/engine/event.php:59 Stack trace: #0 xxx/system/storage/modification/system/engine/loader.php(140): Event->trigger('language/en-gb/...', 'en-gb') #1 xxx/system/framework.php(136): Loader->language('en-gb') #2 xxx/system/startup.php(104): require_once('xxx/...') #3 xxx/install/index.php(37): start('install') #4 {main} thrown in xxx/system/engine/event.php on line 59
I got this issue when I tried to upgrade from OpenCart 2 to 3. In my case it was related to extensions so I had to disable each one of them before proceeding to update. But after I started the installation process It was too late because I had no more access to the admin panel. If you’re in the same position than try this:
Disable OCMod extensions using FTP:
You can also use the file manager of your host account to perform this. Simply rename the folder system/storage/modification to a different name like system/storage/modification_temp. This will temporarily disable all your old OCMod extensions. But don’t forget to create a new empty folder with the same name modification because OpenCart will need that in order to proceed with the installation. Once the installation is done you can enable your extensions again. You preferably need to do that one extension at a time. That way you’ll be able to know which one of your extensions is responsible of a any potential error.
Disable OCMod extensions from database:
If the previous solution didn’t work then you may perform this as an extra step. You need to access your database from your host panel. Look for phpmyadmin or a similar tool, then access the oc_modification table on your OpenCart’s database. There you should find all your extension. You can disable them by changing each row’s status col value to 0 or you can simply execute this mySql query which will do the work for you automatically:
update `oc_modification` set status=0
Make sure to replace oc_modification by the correct name of your current table. The table may have a different prefix like mysite_ instead of oc_, in this case the query should be:
update `mysite_modification` set status=0
3.Warning: fopen(/storage/cache/cache.catalog.language.): failed to open stream: No such file or directory in xxx/system/library/cache/file.php on line 49
I faced this issue after installing OpenCart 3 and trying to move the “storage” folder outside its initial directory as per Opencart’s suggestion. After you install OpenCart 3 and you access your admin panel, a popup (Importan Security Notification) will appear with the following message: ” It is very imporant that you move the storage directory outside of the web directory (e.g. public_html, www or htdocs).”
Now the problem may also in case you clicked on “move” and the process didn’t go well. or if you tried to move the directory manually in an incorrect way. In both cases here’s what you need to make sure of:
Make sure the folder “storage” is in the right location
In the very beginning, the directory storage is supposed to be in the system directory right within your root directory but its location should change according to the OpenCart system notification. Therefore it should move to the root directory. In other words move the system/storage folder to the parent folder, your root directory should now look like:
Make sure the config.php files are pointing to the right location
Opencart has two config.php files: one is location within the root directory and the other inside the admin directory. Both files has paths that points to the storage directory and you need to make sure that the paths are corrects, in order to do this, edit both files and change this line:
define('DIR_STORAGE',....
to this;
define('DIR_STORAGE', '/storage/');
But this might not work sometimes. Because the paths are relative so the root folder may sometime be longer than a simple slash ( / ). The trick here is to find the absolute path to your root directory. It can be something like /usr/www/users/xxxx/ or /home/xxxx/public_html … depending on your host provider so in order to be sure just copy the path from the config.php file itself, see the picture below:
4. Warning: fopen(xxxxx/storage/logs/openbay.log): failed to open stream: No such file or directory in xxxxx/system/library/log.php on line 22
This issue may happen if you have got the popup Important Security Notification on your admin panel (see issue 3) and you clicked on the red move button but it didn’t go well. If this is the case then using your ftp client or your host file manager go and take a look at the storage folder within your root directory and make sure its content looks like this:
if you have a different content, like missing folders than it means that the storage directory hasn’t been moved correctly by OpenCart that’s why you need to do it manually so just delete the incomplete storage folder from your root directory then move the original one that you should find within the folder system then place it where the previous storage folder (the one you deleted previously) was located (the root directory), read the issue 3 for more information about this process.
5.Warning: fopen(xxxx/catalog/view/theme//stylesheet/bootstrap.css): failed to open stream: No such file or directory in xxxxx/catalog/controller/startup/sass.php on line 14
this rare issue happens when OpenCart tries to load your theme name from the database without results, that’s why the link is inccorect : xxxx/catalog/view/theme//stylesheet/bootstrap.css so in order for the file to load correctly, the path should look like: xxxx/catalog/view/theme/default/stylesheet/bootstrap.css for example so this is how to force OpenCart to display the correct theme name:
Save your theme from the admin panel
open the admin panel and go to extensions>extensions then chose theme in the drop-down , a list of your installed themes should appear:
click on the blue edit button located in the same row as your active theme (the one with “enabled”) then without even making any specific modification just save and go test if that has resolved the issue.
make sure your oc_settings table is correct
this solution is tricky because I don’t have a code you can just copy past somewhere into your code or phpmyadmin, you need to open your phpmyadmin and compare your oc_settings table to a correct one, I fixed mine by importing a freshly created OpenCart 3 oc_settings table into my store’s database, by replacing my incorrect table with the correct one, the issue was gone but be careful because this means you’ll have to lose your old settings, I didn’t mind setting everything like it was manually as this would take less time than looking for a solution that would save my previous settings.
6. No input file specified
After installation, your store is redirecting you back to the install page with a message saying “No input file specified”, this problem is related to php and can be resolved by adding this line to your php.ini file:
cgi.fix_pathinfo = 1;
the php.ini file can be found in your website root folder. If it is not there. You can create one and add that line inside it.
Opencart Admin Panel Issues
1. Warning: You do not have permission to access the API!
Have you tried to edit or delete an order on your opencart system without any success? if you’re getting a message like:
chances are you don’t have permissions to access opencart’s api but don’t panic this should be a simple fix.
Make sure your ip address is authorized in the API section
login to your panel and go to System>Users>API
click on edit and go to IP Addresses and add your ip address there then save. this should be the most common reason why you can’t delete or edit your orders but if it doesn’t work try the next suggestion.
Make sure your user group has all the permissions
The administrator group is supposed to have all the permissions by default but give it a look in case it has changed somehow. go to System>User>User Groups
make sure all Access Permissions and Modify Permissions are checked, check them if not then save.
Disable API IP checks once and for all
if you have a dynamic IP the previous solutions might not suit you as you have to reproduce them each time your ip changes, so instead of adding your ip manually each time you can just apply this solution which will relief you once and for all from this annoying task; simply install this extension and it will do the work for you automatically, don’t forget to clear your store’s cache after install.
2.Notice: Trying to access array offset on value of type null in /storage/vendor/scss.inc.php on line 1753
This issue suddenly started showing up when I try to access my opencart admin panel. In order to fix it you need to change line 1753 of the file scss.inc.php If like me, this error message unexpectedly started appearing in admin panel login page, then your hosting provider has probably updated your server php version. You can find the file in the /storage/vendor/ directory. The initial line of code should look like
$key = $key[1];
and in order to get rid of the error message you need to replace it with this:
$key = isset($key[1]) ? $key[1] : null;
3. Unknown: Array and string offset access syntax with curly braces is deprecated
This error message popped up to me when I tried to go to the settings page, as you might guess this is nothing but a php 8 compatibility error and can be fixed easily. All you have to do is to edit the file indicated by the error message. In my case it was /system/library/kadb.php on line 66.
The checkout page is where people connect their payment cards. There’s no worse place for errors to occur.
1. There was an error fetching the PayPal token
This error message used to show up in my client’s OpenCart store checkout page. People were not able to pay through paypal express when they reach step 4: Confirm Order. This issue happens because you’re using the paypal express extension which has stopped from working. You have to install the new paypal extension called PayPal Commerce Platform Integration First, connect to your opencart account and download the extension zip file. Then, go to your OpenCart admin>Extensions>Installer and upload the file you just downloaded. After that, go to Extensions>Extensions and select payments from the filter. Look for PayPal Commerce Platform and click on the plus button to install it. Click now on the pencil button to edit the extension. In here you need to change the status to enabled and connect your store’s paypal account. Your clients can now pay through paypal without a problem. Finally, don’t forget to disable and uninstall the PayPal Express Checkout extension as it is no more needed.
I’ve been working on a wordpress project in which I had to use vimeo’s api in order to upload a video from the client’s server to his vimeo’s account. The website is a directory of mental therapists and doesn’t only offer a large database of professionals but also allow any unsubscribed therapist to join the site and have his own personal page listed in my clien’ts database through a form of course, so among all the details that a therapist can add to his profile there was this field named “business video link” which allows the user to place a link to a preventative video of him or his business but my client wanted more than that, he asked for the option to upload and host a video in a video streaming website from his site then to automatically show it within the therapist’s profile once the upload is done.
My client had a preference for Vimeo so I started reading their API documentation before engaging in the project. I must admit that it was documented in a clear and friendly way, at the beginning, I believed I could finish the project in no more than two hours because all I thought I will have to do is to add a simple file input in the front-end and just copy some ready php code from Vimeo’s website and past it in the client’s back-end but it turned out that I was wrong. In fact, I lost 3 days on this project, 90% of the time I was debugging and looking why the code isn’t working as supposed. This tutorial will show you how to create a simple working form that uploads a video to Vimeo using PHP. The initial code is provided by Vimeo itself but if you have to come across the same path as me then this tutorial is just going to save you 3 days of unnecessary struggle by giving you the version of code I have come to at the end.
What you need:
before creating your own form, make sure you have the following:
An access token provided by Vimeo
Client id and client secret provided by Vimeo
Upload permission enabled on your Vimeo’s app page
How to get it
first step is to create your app page on Vimeo, just go to the developer section of their site: https://developer.vimeo.com/ then click on “new app”. After creating your app, go here https://developer.vimeo.com/apps and chose the app you just created
–make sure you request an upload access, without this the form won’t work as you’re only going to get an error, the request may take time before it gets processed, it took 3 days in my case.
-Generate an access token, chose the same options as the image:
– Now just take the client id, access token and client secret from there
Now just use those information to generate your form
Problems you may encounter:
the code may not work directly from the first shot, if this is the case make sure you do the following: -try the code on your localhost before you test it on your server -first try with small size video file (maybe a 1mo video file) -raise the upload max limit and max execution time on your server/localhost php configuration, you can just add the following code to your .htaccess file:
It is hard to browse the internet through the eyes of a web developer because you don’t see the web like the others do, if you too are a web developer you might know what I am talking about, I am unable to visit a website without starting to look for design flaws rather than focusing on the content but this is really negligible because it can be worse, I am talking about SEO, the day I put my foot in this domain my life on the internet has changed, in fact I started seeing things from a very different perspective which led me to a total loss of taste for reading web content, it has become impossible to read a web article without this feeling of bitterness, you can’t help but notice that something crucial is missing yet the sentences seems well formatted, they still don’t sound natural which makes sens because a tremendous number of web articles are being written according to SEO rules rather than human ituition, if you go for your intuition you probably will achieve a more authentic article than what’s being read now, however that won’t help you reach anyone as far as google is still the primary canal to bring visitors to your article, like almost all websites and blogs 80% of your website visitors would come from google, of course only if you obey to it’s rules, but those rules are so demanding that you’ll find yourself unable to satisfy them without letting go of your authenticity so most of the good writers are turning into WordPress zombies breathing heavily and typing really fast on their keyboards, good writers who refused to surrender are being repressed and left in the last pages of the searches results, and bad writers does have now a strategy to bypass good writers and they’re actually too good at that but for them writing is secondary, this ecosystem seem to maintain itself perfectly well because internet is being populated faster and faster over the years but at which price? quality has deceased immensely since the time, I remember how Internet was like a decade ago, content was more natural, interesting and entertaining, now it looks more like a labyrinth full of disguised bad content traps, I can’t remember how it feels like to read a unique blog article anymore. I’d like you to consider StraightDeveloper as a safe blog, no article has been written under the rules of the SEO, look by yourself, there’s no more than a title and a paragraph in this article, I might not even be sure that I am respecting the english language rules correctly. What you read is my real thoughts without any filters.
I won’t start talking about myself and what I achieved so far, everyone does that, I mean every blog owner is either a special guy with a tremendous experience or some kind of illuminated person who decided to take his egocentricity to a wider scale